# python学习 至此开始
# 学习日期: 2023/10/29 9:49
# 学习者: 任磊


# 导入所需的库
import os
import time
from base64 import b64encode, b64decode
from socket import *
from gmssl import func, sm2, sm3
import pysm4
import string
import random
import threading
import SystemSign
import tkinter as tk
from tkinter import messagebox
from PIL import ImageTk, Image
# import SystemVerify
# import pyautogui
import binascii
import hmac
import hashlib
import secrets
import gmpy2
import re


# 创建密码库调用类
class Crypto_program(object):
    def __init__(self):
        super().__init__()

    sys_time_key = None  # 系统默认生成的临时通行密钥
    self_sm2_public_key = ""  # 用户的SM2公钥
    self_sm2_private_key = ""  # 用户的SM2私钥
    self_sm2_crypto = ""  # 用户自己的SM2加解密体
    self_private_key = ""  # 用户的身份私钥
    self_public_key = ""  # 用户的身份公钥
    self_share_public_key = ""  # 用户的预共享公钥
    self_share_private_key = ""  # 用户的预共享公钥的私钥
    self_share_public_key_sign = "None"  # 用户的预共享公钥的签名
    self_time_key_list = []  # 用户一次性公私钥对列表
    time_public_key = ""  # 用于X3DH主动计算，生成的临时公钥
    # time_private_key = ""  # 用于X3DH主动计算，生成的临时私钥  单因为需要及时删除，故不采用在此定义
    other_get_key_name_list = []  # 已获得公钥的其他用户名列表
    other_get_time_key_list = []  # 已获得的一次性公钥的列表
    other_get_x3dh_key_list = []  # 已获得的x3dh生成密钥的列表
    self_get_x3dh_time_key_list = []  # 为获得x3dh密钥使用的临时私钥对应的公钥
    x3dh_p = 0  # 默认情况下，取默认值
    x3dh_g = 0  # 默认情况下，取默认值
    x3dh_q = 0  # 默认情况下，取默认值
    # 双棘轮算法所需参数
    """
    通过对方新旧密钥的更新比对，将决定用户是否生成新的临时公私钥对
    """
    kdf_chain_random_data = ""  # 双棘轮的中间值
    kdf_dh_self_time_private_key = ""  # 自己的临时私钥
    kdf_dh_self_time_public_key = ""  # 自己的临时公钥
    kdf_dh_other_new_time_public_key = ""  # 对方新临时公钥
    kdf_dh_other_old_time_public_key = ""  # 对方旧临时公钥

    # 随机生成对称密钥的方法(若输入非法，则默认输出 16 字节长度 sm4)
    @staticmethod
    def random_key_born(key_long):
        # 判断输入是否非法
        if type(key_long) == int:
            if int(key_long) > 0:
                pass
            else:
                key_long = - int(key_long)
        else:
            key_long = 16
        # 生成密钥
        words = string.ascii_lowercase + string.ascii_uppercase + string.digits + string.punctuation
        # 根据长度随机采样几个字符，得到一个列表
        chosen = random.sample(words, key_long)
        # 将列表的每个元素，拼接成一个大字符串
        # 赋值密钥
        end_key = "".join(chosen)
        # 返回随机生成的密钥
        return end_key

    # 创建数据可以直接进行SM3哈希的方法（此处直接输入 str型）  返回消息的哈希值
    @staticmethod
    def sm3_data_hash(data):
        # 进行数据类型的判断
        if type(data) is not bytes:
            time_data = func.bytes_to_list(data.encode('utf-8'))
            hash_data = sm3.sm3_hash(time_data)
            # 返回输入值的hash值
            return hash_data
        else:
            pass

    # 对称密钥基础强度检测，合法性检测的方法(long: 限制的最大长度)
    @staticmethod
    def test_key_strong(key, long):
        pass_flag1 = False
        pass_flag2 = False
        # 判断传入数据的合法性
        if type(long) != int:
            long = 8
        else:
            if int(long) < 8:
                long = 8
            else:
                long = int(long)
        # 检测密钥长度
        key_long = key.encode()
        if 8 <= len(key_long) <= long:
            # 检测是否含有数字
            for word1 in key:
                if word1.isalnum():
                    pass_flag1 = True
                    break
            # 检测是否含有字母
            for word2 in key:
                if word2.isalpha():
                    pass_flag2 = True
                    break
            if pass_flag1 is True and pass_flag2 is True:
                return True
            else:
                return False
        else:
            return False

    # 定义 X3DH 协议下的共享密钥生成方法  主动生成  基于离散对数的数学难题
    @staticmethod
    def x3dh_active_create(other_name, other_sm2_public_key, other_public_key, other_share_public_key, other_share_public_key_sign, other_time_public_key):  # 其中参数均为对方的数据
        pass_flag = False
        # print("正在验证对方预共享公钥...")
        Connection_program.show_sever_key_get_text.insert("end", "正在验证对方预共享公钥...\n")
        other_sm2_crypto = Crypto_program.init_sm2_struct(other_sm2_public_key, "")
        # 使用对方的SM2公钥对对方的预共享公钥进行验签
        if other_sm2_crypto.verify(other_share_public_key_sign, sm3.sm3_hash(func.bytes_to_list(other_share_public_key.encode())).encode()):
            # print("对方预共享公钥验证成功")
            Connection_program.show_sever_key_get_text.insert("end", "对方预共享公钥验证成功！\n")
            pass_flag = True
        else:
            # print("\033[91m对方预共享公钥验证失败\033[0m")
            Connection_program.show_sever_key_get_text.insert("end", "对方预共享公钥验证失败！\n")
        # 检测当前用户是否拥有公私钥数据文件
        if os.path.exists("client(3.50)" + Main_program.name + ".txt"):
            pass
        else:
            # 若无公私钥对数据文件，则创建
            Crypto_program.create_client_key(1)
        # 初始化获得用户公私钥对数据
        File_program.get_client_all_key_data()
        if pass_flag is True:
            # 调用获得用户自己密钥对数据的方法
            File_program.get_client_all_key_data()
            # 调用初始化获得 p 的方法
            File_program.init_x3dh_p_g()
            # 生成临时公私钥对
            self_time_private_key, self_time_public_key = Crypto_program.gen_IDkey(Crypto_program.x3dh_g, Crypto_program.x3dh_p)
            # 调用生成自己在X3DH协议下的公私钥对的方法
            dh1 = Crypto_program.dh(Crypto_program.self_private_key, other_share_public_key)  # 己方身份私钥， 对方预签名公钥
            # print("DH1的值为:{}".format(dh1))
            Connection_program.show_sever_key_get_text.insert("end", "DH的值为:{}\n".format(dh1))
            dh2 = Crypto_program.dh(self_time_private_key, other_public_key)  # 己方临时生成公钥对应的私钥， 对方身份公钥
            # print("DH2的值为:{}".format(dh2))
            Connection_program.show_sever_key_get_text.insert("end", "DH2的值为:{}\n".format(dh2))
            dh3 = Crypto_program.dh(self_time_private_key, other_share_public_key)  # 己方临时生成公钥对应的私钥， 对方预签名公钥
            # print("DH3的值为:{}".format(dh3))
            Connection_program.show_sever_key_get_text.insert("end", "DH3的值为:{}\n".format(dh3))
            if other_time_public_key != "NONE":  # 判断一次性公钥是否为空
                dh4 = Crypto_program.dh(self_time_private_key, other_time_public_key)  # 己方临时生成的公钥对应的私钥， 对方一次性公钥
                # print("DH4的值为:{}".format(dh4))
                Connection_program.show_sever_key_get_text.insert("end", "DH4的值为:{}\n".format(dh4))
            else:
                # print("由于对方无一次性公钥，故DH4值为空")
                Connection_program.show_sever_key_get_text.insert("end", "由于对方五一次性公钥，故DH4的值为空\n")
                dh4 = ""
            """
            # 此为测试用数据
            print("本次计算中")
            print("己方身份私钥:{}".format(Crypto_program.self_private_key))
            print("己方身份公钥:{}".format(Crypto_program.self_public_key))
            print("己方的临时私钥:{}".format(self_time_private_key))
            print("己方的临时公钥:{}".format(self_time_public_key))
            print("对方的身份公钥:{}".format(other_public_key))
            print("对方的预共享公钥:{}".format(other_share_public_key))
            print("对方的一次性公钥:{}".format(other_time_public_key))
            """
            dhf = str(dh1) + str(dh2) + str(dh3) + str(dh4)  # 将四次dh计算的值拼接
            sk = Crypto_program.create_sha256_signature(dhf, str(Main_program.name) + other_name)  # 进行摘要计算获得x3dh协议下的协商秘钥
            return True, sk, self_time_public_key  # 返回获得的协密钥,以及对应临时使用的私钥对应的公钥
        else:
            return False, None, None

    # 定义 X3DH 协议下的共享密钥生成的方法  被动生成  基于离散对数的数学难题  通常为计算后的即时通信，故未对计算结果进行保存
    @staticmethod
    def x3dh_passive_create(self_time_public_key, other_name, other_public_key, other_time_public_key):  # 参数依次为 己方一次性公钥，对方身份公钥，对方一次性公钥
        next_flag = False
        self_time_private_key = ""
        # 调用获得用户自己密钥对数据的方法
        File_program.get_client_all_key_data()
        # 调用初始化获得 p 的方法
        File_program.init_x3dh_p_g()
        # 根据传入的我方一次性公钥，找出对应的一次性私钥
        num = len(Crypto_program.self_time_key_list)
        if self_time_public_key != "":
            for i in range(0, num - 1):
                if Crypto_program.self_time_key_list[i] == self_time_public_key:  # 判断是否为目标一次性公钥
                    self_time_private_key = Crypto_program.self_time_key_list[i + 1]  # 获得对应的一次性私钥
                    next_flag = True
                    break
                else:
                    pass
        else:
            next_flag = True
        if next_flag is True:
            # 己方预签名公钥对应的私钥，对方身份公钥
            dh1 = Crypto_program.dh(Crypto_program.self_share_private_key, other_public_key)
            # print("dh1的值为: {}".format(dh1))
            Connection_program.wait_mode_text.insert("end", "dh1的值为:{}\n".format(dh1))
            # 己方身份公钥对应的私钥，对方的临时公钥
            dh2 = Crypto_program.dh(Crypto_program.self_private_key, other_time_public_key)
            # print("dh2的值为: {}".format(dh2))
            Connection_program.wait_mode_text.insert("end", "dh2的值为:{}\n".format(dh2))
            # 己方预签名公钥对应的私钥， 对方的临时公钥
            dh3 = Crypto_program.dh(Crypto_program.self_share_private_key, other_time_public_key)
            # print("dh3的值为: {}".format(dh3))
            Connection_program.wait_mode_text.insert("end", "dh3的值为:{}\n".format(dh3))
            # 己方一次性公钥对应的私钥，对方临时公钥
            if self_time_public_key != "":
                dh4 = Crypto_program.dh(self_time_private_key, other_time_public_key)
                # print("dh4的值为: {}".format(dh4))
                Connection_program.wait_mode_text.insert("end", "dh4的值为:{}\n".format(dh4))
            else:
                dh4 = ""
                # print("d4的值为空")
                Connection_program.wait_mode_text.insert("end", "dh4的值为空\n")
            # 对获得的各个值进行拼接
            dhf = str(dh1) + str(dh2) + str(dh3) + str(dh4)
            # 进行摘要计算获得x3dh协议下的协商秘钥
            sk = Crypto_program.create_sha256_signature(dhf, other_name + str(Main_program.name))
            """
            暂时处于注释状态，测试完成后启用该部分代码
            # 对该次计算损耗的一次性公私钥对进行删除
            if File_program.update_client_all_data(self_time_public_key, self_time_private_key):  # 判断目标一次性公私钥对移除返回结果
                print("本次计算所使用的一次性公私钥对，已从用户公私钥对数据文件中删除")
            else:
                print("\033[91m本次计算所使用的一次性性公私钥对移除失败，\033[0m")
            """
            return True, sk  # 返回计算获得的X3DH协商密钥
        else:
            # print("\033[91m未能找到临时公钥对应的私钥\033[0m")
            Connection_program.ready_text.config(state="normal")
            Connection_program.ready_text.delete("1.0", "end")
            Connection_program.ready_text.insert("end", "未能找到临时公钥对应的私钥！\n")
            Connection_program.ready_text.config(state="normal")
            return False, None

    # 定义双棘轮算法加密函数
    """
    只有当双发交替的发送消息时，kdf棘轮与dh棘轮才会同时转动，即不断地生成临时公私钥对
    单方向的重复发送消息，仅转动kdf棘轮，不会生成新的公私钥对
    """
    @staticmethod
    def kdf_dh_encry_function(data):
        if Crypto_program.kdf_dh_other_new_time_public_key != Crypto_program.kdf_dh_other_old_time_public_key:  # 判断是否获得对方新的公钥
            # 生成临时公私钥对
            Crypto_program.kdf_dh_self_time_private_key, Crypto_program.kdf_dh_self_time_public_key = Crypto_program.gen_IDkey(Crypto_program.x3dh_g, Crypto_program.x3dh_p)
        password = Crypto_program.kdf_chain_random_data
        salt = Crypto_program.dh(Crypto_program.kdf_dh_self_time_private_key, Crypto_program.kdf_dh_other_new_time_public_key)
        time_signal_key = Crypto_program.create_sha256_signature(password, str(salt))
        # 取生成部分的前 16 位作为本次加密的密钥
        en_data = pysm4.encrypt_ecb(data, time_signal_key[0:15])
        # print("本次使用的加密密钥为:{}".format(time_signal_key[0:15]))
        Connection_program.ready_text.config(state="normal")
        Connection_program.ready_text.delete("1.0", "end")
        Connection_program.ready_text.insert("end", "本次使用的加密密钥为:{}".format(time_signal_key[0:15]))
        Connection_program.ready_text.config(state="disabled")
        # 余下部分作为下一次的 password 输入
        Crypto_program.kdf_chain_random_data = time_signal_key[15:64]
        # 更新对方公钥
        Crypto_program.kdf_dh_other_old_time_public_key = Crypto_program.kdf_dh_other_new_time_public_key
        return en_data

    # 定义双棘轮算法解密函数
    @staticmethod
    def kdf_dh_decry_function(en_data):
        password = Crypto_program.kdf_chain_random_data
        salt = Crypto_program.dh(Crypto_program.kdf_dh_self_time_private_key, Crypto_program.kdf_dh_other_new_time_public_key)
        time_signal_key = Crypto_program.create_sha256_signature(password, str(salt))
        data = pysm4.decrypt_ecb(en_data, time_signal_key[0:15])
        # print("本次使用的解密密钥为:{}".format(time_signal_key[0:15]))
        Connection_program.ready_text.config(state="normal")
        Connection_program.ready_text.delete("1.0", "end")
        Connection_program.ready_text.insert("end", "本次使用的解密密钥为:{}".format(time_signal_key[0:15]))
        Connection_program.ready_text.config(state="disabled")
        Crypto_program.kdf_chain_random_data = time_signal_key[15:64]
        # 返回解密后的数据
        return data

    # 创建用户自己公私钥对(包括SM2公私钥对)及相关数据的方法
    @staticmethod
    def create_client_key(mode=1,):  # 参数为: 生成公私钥对使用的p,g的参数，(1 使用默认p,g， 2 重新生成)
        if mode == 1:
            File_program.init_x3dh_p_g()  # 调用 x3dh协议下的 p, g 初始化的方法
            Crypto_program.self_private_key, Crypto_program.self_public_key = Crypto_program.gen_IDkey(Crypto_program.x3dh_g, Crypto_program.x3dh_p)  # 获得用户的身份公私钥对
            Crypto_program.self_share_private_key, Crypto_program.self_share_public_key = Crypto_program.gen_IDkey(Crypto_program.x3dh_g, Crypto_program.x3dh_p)  # 获得用户的预共享公私钥对
            for _ in range(5):
                time_private_key, time_public_key = Crypto_program.gen_IDkey(Crypto_program.x3dh_g, Crypto_program.x3dh_p)  # 获取每次生成的一次性公私钥对
                Crypto_program.self_time_key_list.append(time_public_key)
                Crypto_program.self_time_key_list.append(time_private_key)
            # 调用SM2公私钥对生成并获取的方法
            Crypto_program.sm2_all_key_born()
            # 调用初始化创建sm2加解密体的方法
            Crypto_program.self_sm2_crypto = Crypto_program.init_sm2_struct(Crypto_program.self_sm2_public_key, Crypto_program.self_sm2_private_key)
            # 使用生成的用户SM2私钥对预共享公钥签名
            Crypto_program.self_share_public_key_sign = Crypto_program.self_sm2_crypto.sign(Crypto_program.sm3_data_hash(str(Crypto_program.self_share_public_key)).encode(), Crypto_program.self_sm2_private_key)
            # 调用创建用户公私钥对数据文件的方法
            File_program.create_client_key_file()
        else:
            pass

    # 生成大质数
    @staticmethod
    def gen_prime(longueur):  # Génère un nombre premier suivant sa longueur  # 根据长度生成质数
        nombreAlea = secrets.randbits(longueur)
        while gmpy2.is_prime(nombreAlea, 25) is False:
            nombreAlea = secrets.randbits(longueur)
        prime = nombreAlea
        return prime

    # 生成 p
    @staticmethod
    def gen_safeprime():  # Génère un nombre fortement premier  生成一个强质数
        while True:
            p = Crypto_program.gen_prime(2048)
            if gmpy2.is_prime((p - 1) // 2) is True:
                print("p : ", p)
                print(p.bit_length())
                return p

    # 生成 G
    @staticmethod
    def gen_elementgen(p):  # Génère un élement générateur avec pour paramètre un nombre fortement premier  生成一个带有强烈质数参数的生成器元素
        q = (p - 1) // 2
        while True:
            alpha = secrets.randbits(512)
            if pow(alpha, 2, p) != 1 & pow(alpha, q, p) != 1 & pow(alpha, p - 1, p) == 1:
                print("alpha:", alpha)
                print("alpha^2:", pow(alpha, 2, p))
                print("alpha^q:", pow(alpha, (p - 1) // 2, p))
                print("alpha^p-1:", pow(alpha, p - 1, p))
                return alpha

    # 定义在X3DH协议下生成用户自己的公私钥对的方法
    @staticmethod
    def gen_IDkey(g, p):  # Permet de générer les clés identités.  允许生成身份密钥。
        print("Génération des clés identités.")  # 身份密钥的生成
        # p = int(fetch_from_server("", "Value_P.txt"))
        # g = int(fetch_from_server("", "Value_G.txt"))
        IDpriv = secrets.randbits(2048)
        IDpub = pow(g, IDpriv, p)
        return IDpriv, IDpub

    @staticmethod  # 拼接三次 DH计算的值 获得最终地共享密钥
    def create_sha256_signature(key, message):
        if len(key) % 2 != 0:
            key = key + "0"
        byte_key = binascii.unhexlify(key)
        message = message.encode()
        return hmac.new(byte_key, message, hashlib.sha256).hexdigest().upper()

    # 定义进行一次 DH 计算的方法
    @staticmethod
    def dh(a, b):
        # p = 11476114425077445636913897780729058814788399522553701049280397688323001276391084717487591797788773737035134819088321086678078901084786890698833590212793893
        p = int(Crypto_program.x3dh_p)
        result = pow(int(b), int(a), p)
        return result

    # 定义调用生成随机SM2密钥对的方法
    @staticmethod
    def sm2_all_key_born():
        # 调用相关文件
        os.system("python E:\python练习\pythonProject\connectionSocket\国密SM2随机生成密钥文件.py")
        # 读取用户公钥
        public_key_file = open("random_public_key_data.txt", "r")
        Crypto_program.self_sm2_public_key = public_key_file.read()
        public_key_file.close()
        # 读取用户私钥
        private_key_file = open("random_private_key_data.txt", "r")
        Crypto_program.self_sm2_private_key = private_key_file.read()
        private_key_file.close()

    # 定义初始化创建 sm2 加解密体的方法   返回sm2加解密体
    @staticmethod
    def init_sm2_struct(sm2_public_key, sm2_private_key):
        sm2_crypto = sm2.CryptSM2(sm2_private_key, sm2_public_key)
        return sm2_crypto

    # 国密SM2加密的方法
    @staticmethod
    def sm2_encrypt(sm2_crypt, info):
        encode_info = sm2_crypt.encrypt(info.encode(encoding="utf-8"))
        encode_info = b64encode(encode_info).decode()  # 将二进制bytes通过base64编码
        return encode_info

    # 国密SM2解密的方法
    @staticmethod
    def sm2_decrypt(sm2_crypt, info):
        decode_info = b64decode(info.encode())  # 通过base64解码成二进制bytes
        decode_info = sm2_crypt.decrypt(decode_info).decode(encoding="utf-8")
        return decode_info


# 创建socket通信类
class Connection_program(object):
    def __init__(self):
        super().__init__()

    # 通信状态
    connect_flag = False
    # 通信端口号
    PORT = 9000
    # 缓冲区大小
    Max_data = 4056
    # 会话状态
    talk_flag = False
    # 当前可进行 X3DH 协议下的通信用户列表
    hang_key_person_list = []
    # 用户程序当前是否可打断标志符号
    client_main_tcb_interrupt_flag = True
    # 客户端用户操作线程中断的标志
    client_main_tcb_interrupt = False
    # 用户端界面线程已中断表示
    client_main_tcb_close = True
    # 关闭客户端接收指令线程标志变量
    client_recv_order_clos = False
    # 注册方法所需参数
    connect_sever_flag = False  # 连接服务端状态
    register_name = ""  # 用户注册名
    register_password_one = ""  # 用户注册密码
    register_password_two = ""  # 用户注册密码确认
    register_button = ""  # 注册按钮
    ready_text = ""  # 就绪提示文本框
    register_socket = ""  # 通信所需的通信体

    # 登录界面所需参数
    login_button = ""  # 登录按钮
    login_name = ""  # 登录用户名
    login_password = ""  # 登录密码
    login_try_time = 0
    login_try_max_time = 4  # 登录最大尝试次数
    login_socket = ""

    # 用户界面所需参数
    interface_public_chat_button = ""
    interface_hang_key_button = ""
    interface_get_key_button = ""
    interface_have_key_button = ""
    interface_private_room_button = ""
    interface_wait_button = ""

    # 公共聊天室界面所需参数
    public_chat_text = ""  # 聊天数据框
    public_chat_entry = ""  # 消息输入框
    public_chat_send_button = ""  # 消息发送按钮
    public_chat_connect_start_button = ""  # 开启通信按钮
    public_chat_connect_close_button = ""  # 结束通信按钮
    public_chat_exit_button = ""  # 退出聊天室模式按钮
    public_chat_connect_flag = False  # 公共聊天室通信中标志

    # 用户查看及上传界面所需参数
    interface_key_sm2_text = ""  # 用户sm2公私钥对
    interface_key_self_text = ""  # 用户身份公私钥对
    interface_key_share_text = ""  # 用户预共享公私钥对
    interface_key_time_text = ""  # 用户一次性公私钥对
    interface_key_send_button = ""  # 用户公钥上传按钮
    interface_key_born_button = ""  # 用户公私钥对生成按钮
    interface_key_exit_button = ""  # 用户退出按钮
    interface_key_ready_flag = False  # 用户是否可以上传公钥数据的标志

    # 服务端公钥及获得公钥展示界面所需参数
    show_sever_key_name_text = ""
    show_sever_key_get_text = ""
    get_key_button = ""  # 发送获取公钥数据按钮
    get_key_num = ""  # 用户目标输入变量
    get_key_num_button = ""  # 用户目标输入按钮
    output_x3dh_key_text = ""  # 用户最终获得x3dh输出栏
    get_key_into_flag = False  # 是否已获得用户名数据标志
    get_key_flag = False  # 用户最终获得公钥的标志

    # 客户端展示已获得的公钥数据展示界面所需的参数
    show_client_key_text = ""  # 数据展示文本框
    show_client_key_mode_text = ""  # 状态显示框
    show_client_key_entry = ""  # 数据输入框
    show_client_key_input_button = ""  # 数据发送按钮
    show_client_key_connect_start_button = ""  # 开启通信按钮
    show_client_key_connect_close_button = ""  # 结束通信按钮
    show_client_key_exit_button = ""  # 退出按钮
    show_client_key_connect_flag = False  # 客户端是否处于通信状态标志

    # 等待模式窗口所需参数
    wait_mode_text = ""  # 消息展示栏
    wait_mode_state_text = ""  # 通信状态栏
    wait_mode_entry = ""  # 输入框
    wait_mode_send_button = ""  # 消息发送按钮
    wait_mode_connect_start_button = ""  # 进入等待按钮
    wait_mode_connect_next_button = ""  # 结束本次通信按钮
    wait_mode_connect_close_button = ""  # 退出等待按钮
    wait_mode_exit_button = ""  # 退出按钮
    wait_mode_alive_flag = False  # 等待模式激活状态标志
    wait_mode_connect_state = 0  # 通信状态标志符  数据说明: 0：未连接到用户， 1：正在判别用户，2：正在与其他用户通信中
    wait_mode_connect_flag = False  # 等待模式通信状态的标志
    # 等待模式标志
    client_wait_mode_flag = False  # 等待模式总启用标志
    client_wait_mode_connect_flag = False  # 用于判断是否与其他用户进行通信连接
    client_wait_mode_x3dh_start_flag = False  # 用于判断是否进行 X3DH 通信验证
    client_wait_mode_ready_flag = False  # 用于判断 X3DH 是否准备完成
    client_wait_mode_x3dh_key = ""  # 用于记录计算在 X3DH 协议下获得的密钥
    client_wait_mode_other_name = ""  # 用于记录对方用户名
    # 聊天室参数
    private_room_mode_flag = False  # 聊天室模式标志
    private_room_talk_flag = False  # 是否处于聊天中标志

    # 聊天室模式窗口所需参数
    private_chat_text = ""  # 消息窗口
    private_chat_member_text = ""  # 房间的成员列表框  此为房主独有的
    private_chat_member_list = ["成员列表", ]  # 房间的成员列表  此为房主独有的
    private_chat_entry = ""  # 消息输入框
    private_chat_send_button = ""  # 消息发送按钮
    private_chat_connect_start_button = ""  # 开启通信的方法  创建房间  或  查询房间
    private_chat_connect_close_button = ""  # 结束通信的按钮
    private_chat_exit_button = ""  # 退出的按钮
    private_chat_room_member_num = 1  # 聊天室成员数量
    private_chat_room_password = "NONE"  # 聊天室口令
    private_chat_host_send_state = 0  # 房主态 发送按钮状态标志
    private_chat_guest_send_state = 0  # 成员态 发送按钮状态标志
    private_chat_room_ready_flag = False  # 房间的参数设置完毕标志
    private_room_host_name_list = []  # 房主名列表  此为成员态独有
    private_room_now_person_num_list = []  # 房间现人数列表  此为成员态独有
    private_room_max_person_num_list = []  # 房间最大容纳人数列表  此为成员态独有
    private_room_encry_list = []  # 房间加密状态列表  此为成员态独有
    """
    private_chat_host_send_state
    0: 无效
    1： 房主态，人数输入
    2： 房主态，密码输入
    3： 房主态，消息发送
    
    private_chat_guest_send_state
    0:无效
    1： 成员态：房间选择
    2： 成员态：密码输入
    3： 成员态：消息发送
    """

    # 设置通信所需的IP配置的函数
    @staticmethod
    def get_host_ip():
        s = socket(AF_INET, SOCK_DGRAM)
        try:
            s.connect(('8.8.8.8', 80))  # 114.114.114.114也是dns地址
            ip = s.getsockname()[0]
        finally:
            s.close()
        return ip

    # 登录界面
    @staticmethod
    def login_window():
        # 使之所需变量参数
        Connection_program.login_name = tk.StringVar()
        Connection_program.login_password = tk.StringVar()
        # 设置窗口参数
        # 登录界面容器
        Window_program.login_frame = tk.Frame(root_window, height=500, width=600, bd=3, padx=15, pady=10)
        Window_program.login_frame.place(anchor="center", relx=0.5, rely=0.5)
        # 登录界面文本
        Connection_program.ready_text = tk.Text(Window_program.login_frame, font=("黑体", 18), fg="red", width=40, height=2, bd=3, padx=10, pady=5)
        Connection_program.ready_text.grid(row=0, columnspan=2, padx=10, pady=10)
        Connection_program.ready_text.config(state="disabled")
        # 提示语
        tk.Label(Window_program.login_frame, text="请输入用户名与用户密码", font=("kaiti", 18), padx=10, pady=10).grid(row=1, columnspan=2, padx=10, pady=10)
        # 用户名
        tk.Label(Window_program.login_frame, text="账户名:", font=("黑体", 15), padx=10, pady=10).grid(row=2, column=0, padx=10, pady=10)
        tk.Entry(Window_program.login_frame, textvariable=Connection_program.login_name, font=("黑体", 13), width=23,).grid(row=2, column=1, padx=10, pady=10)
        # 用户密码
        tk.Label(Window_program.login_frame, text="密码:", font=("黑体", 15), padx=10, pady=10).grid(row=3, column=0, padx=10, pady=10)
        tk.Entry(Window_program.login_frame, textvariable=Connection_program.login_password, show="*", font=("黑体", 13), width=23).grid(row=3, column=1, padx=10, pady=10)
        # 登录按钮
        Connection_program.login_button = tk.Button(Window_program.login_frame, text="登录", font=("黑体", 15), relief="raised", fg="green", padx=5, pady=5, command=Connection_program.start_login_connect)
        Connection_program.login_button.grid(row=4, column=0, padx=10, pady=10)
        # 取消按钮
        tk.Button(Window_program.login_frame, text="取消", fg="red", font=("黑体", 15), anchor="center", padx=5, pady=5, command=Connection_program.login_window_to_start_window).grid(row=4, column=1, padx=10, pady=10)

    # 登录界面转向其他界面的方法
    @staticmethod
    def login_window_to_start_window():
        Window_program.login_frame.destroy()
        Main_program.start_application()

    @staticmethod
    def login_window_to_interface_window():
        Window_program.login_frame.destroy()
        Connection_program.interface_window()

    # 开启通信的方法  登录模式
    @staticmethod
    def start_login_connect():
        connect_able_flag = False
        # 截止本次登录结束，登录按钮失效
        Connection_program.login_button.config(state="disabled")
        # 发送登录请求预处理
        login_name = Connection_program.login_name.get()
        login_password = Connection_program.login_password.get()
        if login_name == "" or login_name == "用户名不能为空！":
            Connection_program.login_name.set("用户名不能为空！")
        else:
            if login_password == "" or login_password == "用户密码不能为空！":
                Connection_program.login_password.set("用户密码不能为空！")
            else:
                connect_able_flag = True
        if Connection_program.login_try_time >= Connection_program.login_try_max_time:  # 判断尝试登录次数
            Connection_program.ready_text.config(state="normal")
            Connection_program.ready_text.delete("1.0", "end")
            Connection_program.ready_text.insert("end", "您的尝试次数已超过限定的 {} 次数，当前已被锁定！".format(Connection_program.login_try_max_time))
            Connection_program.ready_text.config(state="disabled")
            connect_able_flag = False
        if connect_able_flag is True:  # 判断是否可以进行通行
            pass_flag = False  # 登录结果判断标志
            # 一旦启动，改变通信状态
            Connection_program.connect_flag = True
            # 通信部分
            IP = Connection_program.get_host_ip()  # 获得本机的IPV4地址
            PORT = Connection_program.PORT  # 设置端口号
            # 设置网络层协议，传输层协议
            data_socket = socket(AF_INET, SOCK_STREAM)  # IP协议，TCP
            # 尝试进行连接
            try:
                data_socket.connect((IP, PORT))
                # 接收随机验证消息
                random_data = data_socket.recv(Connection_program.Max_data).decode()
                # 发送签名消息
                sign_hash_data = SystemSign.system_sign_message(random_data)
                data_socket.send(sign_hash_data.encode())
                # print("正在尝试连接服务端...")
                Connection_program.ready_text.config(state="normal")
                Connection_program.ready_text.delete("1.0", "end")
                Connection_program.ready_text.insert("end", "正在尝试连接服务端...")
                Connection_program.ready_text.config(state="disabled")
                # 接收验证结果
                result_data = data_socket.recv(Connection_program.Max_data).decode()
                if result_data == "OK":
                    # print("连接服务端成功")
                    data_socket.send("@sever_connect_mode1".encode())  # 发送通信模式  登录模式
                    time.sleep(0.5)
                    # 将用户名发送至客户端
                    data_socket.send(login_name.encode())
                    # 接收来自客户端的用户是否存在判断结果
                    flag = data_socket.recv(Connection_program.Max_data).decode()
                    Connection_program.ready_text.config(state="normal")
                    Connection_program.ready_text.delete("1.0", "end")
                    if flag == "True":
                        # 进行用户密码的验证
                        hash_password = sm3.sm3_hash(func.bytes_to_list(login_password.encode()))  # 获得用户输入密码的 hash 值
                        # 发送用户密码的哈希值至客户端
                        data_socket.send(hash_password.encode())
                        # 接收服务端的判断结果
                        flag = data_socket.recv(Connection_program.Max_data).decode()
                        if flag == "True":
                            # print("登录成功！")
                            Connection_program.ready_text.insert("end", "登录成功！")
                            Main_program.name = login_name  # 更新用户的账户数据
                            Main_program.password = login_password
                            Connection_program.login_try_time = 0
                            pass_flag = True
                        else:
                            # print("\033[91m 登录失败！\033[0m")
                            Connection_program.ready_text.insert("end", "登录失败！")
                            Connection_program.login_try_time += 1
                    else:
                        # print("\033[91m 不存在该用户！\033[0m")
                        Connection_program.ready_text.insert("end", "不存在该用户！")
                        Connection_program.login_try_time += 1
                    Connection_program.ready_text.config(state="disabled")
                else:
                    # print("\033[91m 连接服务端失败 \033[0m")
                    Connection_program.ready_text.config(state="normal")
                    Connection_program.ready_text.delete("1.0", "end")
                    Connection_program.ready_text.insert("end", "连接服务端失败！")
                    Connection_program.ready_text.config(state="disabled")
            except ConnectionRefusedError:  # 检测连接状况
                Connection_program.ready_text.config(state="normal")
                Connection_program.ready_text.delete("1.0", "end")
                Connection_program.ready_text.insert("end", "服务器不在工作状态或维护中!")
                Connection_program.ready_text.config(state="disabled")
                Connection_program.login_button.config(state="normal")
            finally:
                # 判断是否通过登录
                if pass_flag is True:
                    Connection_program.login_socket = data_socket
                    Connection_program.login_window_to_interface_window()  # 改变界面显示
                else:
                    data_socket.close()
                    Connection_program.login_button.config(state="normal")

    # 用户界面窗口
    @staticmethod
    def interface_window():
        # 设置窗口参数
        # 登录界面容器
        Window_program.interface_frame = tk.Frame(root_window, height=500, width=600, bd=3, padx=15, pady=10)
        Window_program.interface_frame.place(anchor="center", relx=0.5, rely=0.5)
        # 提示文本框
        Connection_program.ready_text = tk.Text(Window_program.interface_frame, font=("黑体", 18), fg="red", width=40, height=2, bd=3, padx=10, pady=5)
        Connection_program.ready_text.insert("end", "欢迎您 {}".format(Main_program.name))
        Connection_program.ready_text.pack(side="top", padx=10, pady=10)
        Connection_program.ready_text.config(state="disabled")
        # 公共聊天室按钮
        Connection_program.interface_public_chat_button = tk.Button(Window_program.interface_frame, width=20, height=1, text="进入公共聊天室", fg="green", font=("黑体", 15), anchor="center", padx=5, pady=5, command=Connection_program.interface_window_to_public_chat_room_window)
        Connection_program.interface_public_chat_button.pack(side="top", padx=10, pady=10)
        # 挂载公钥按钮
        Connection_program.interface_hang_key_button = tk.Button(Window_program.interface_frame, width=20, height=1, text="查看及上传公钥", fg="green", font=("黑体", 15), anchor="center", padx=5, pady=5, command=Connection_program.interface_window_to_interface_key_window)
        Connection_program.interface_hang_key_button.pack(side="top", padx=10, pady=10)
        # 获得公钥按钮
        Connection_program.interface_get_key_button = tk.Button(Window_program.interface_frame, width=20, height=1, text="查询及获得公钥", fg="green", font=("黑体", 15), anchor="center", padx=5, pady=5, command=Connection_program.interface_window_to_show_sever_key_window)
        Connection_program.interface_get_key_button.pack(side="top", padx=10, pady=10)
        # 查看已获得的公钥按钮
        Connection_program.interface_have_key_button = tk.Button(Window_program.interface_frame, width=20, height=1, text="查看已获得公钥", fg="green", font=("黑体", 15), anchor="center", padx=5, pady=5, command=Connection_program.interface_window_to_show_client_key_window)
        Connection_program.interface_have_key_button.pack(side="top", padx=10, pady=10)
        # 聊天室按钮
        Connection_program.interface_private_room_button = tk.Button(Window_program.interface_frame, width=20, height=1, text="进入聊天室模式", fg="green", font=("黑体", 15), anchor="center", padx=5, pady=5, command=Connection_program.interface_window_to_private_chat_room_window)
        Connection_program.interface_private_room_button.pack(side="top", padx=10, pady=10)
        # 等待模式按钮
        Connection_program.interface_wait_button = tk.Button(Window_program.interface_frame, width=20, height=1, text="进入等待模式", fg="green", font=("黑体", 15), anchor="center", padx=5, pady=5, command=Connection_program.interface_window_to_wait_mode_window)
        Connection_program.interface_wait_button.pack(side="top", padx=10, pady=10)
        # 退出登录按钮
        tk.Button(Window_program.interface_frame, width=20, height=1, text="退出登录", fg="red", font=("黑体", 15), anchor="center", padx=5, pady=5, command=Connection_program.interface_window_to_start_window).pack(side="top", padx=10, pady=10)

    # 由用户界面转向其他界面
    @staticmethod
    def interface_window_to_start_window():
        # 向服务端发送退出登录提示
        Connection_program.login_socket.send("@sever_connect_end".encode())
        Connection_program.login_socket.close()
        Connection_program.client_main_tcb_close = True
        # 转向初始界面
        Window_program.interface_frame.destroy()
        Main_program.start_application()

    @staticmethod
    def interface_window_to_interface_key_window():
        Window_program.interface_frame.destroy()
        Connection_program.interface_key_window()

    @staticmethod
    def interface_window_to_show_sever_key_window():
        Window_program.interface_frame.destroy()
        Connection_program.show_sever_key_window()

    @staticmethod
    def interface_window_to_show_client_key_window():
        Window_program.interface_frame.destroy()
        Connection_program.show_client_key_window()

    @staticmethod
    def interface_window_to_wait_mode_window():
        Window_program.interface_frame.destroy()
        Connection_program.wait_mode_window()

    @staticmethod
    def interface_window_to_public_chat_room_window():
        Window_program.interface_frame.destroy()
        Connection_program.public_chat_room_window()

    @staticmethod
    def interface_window_to_private_chat_room_window():
        Window_program.interface_frame.destroy()
        Connection_program.private_chat_room_mode_window()

    # 公共聊天室界面
    @staticmethod
    def public_chat_room_window():
        # 设置窗口所需参数
        Window_program.public_chat_room_frame = tk.Frame(root_window, height=500, width=950, bd=3, padx=15, pady=10)
        Window_program.public_chat_room_frame.place(anchor="center", relx=0.5, rely=0.5)
        # 界面标语
        tk.Label(Window_program.public_chat_room_frame, padx=10, pady=10, font=("黑体", 15), text="公共聊天室界面", fg="black", ).grid(row=0, column=0, columnspan=3, padx=10, pady=10, )
        # 聊天数据框
        Connection_program.public_chat_text = tk.Text(Window_program.public_chat_room_frame, height=30, width=100, bd=3, font=("黑体", 10), fg="black", padx=10, pady=10)
        Connection_program.public_chat_text.config(state="disabled")
        Connection_program.public_chat_text.grid(row=1, column=0, columnspan=3, padx=10, pady=10)
        # 提示消息框
        Connection_program.ready_text = tk.Text(Window_program.public_chat_room_frame, height=2, width=70, bd=3, font=("黑体", 15), fg="red", padx=10, pady=10)
        Connection_program.ready_text.config(state="disabled")
        Connection_program.ready_text.grid(row=2, column=0, columnspan=3, padx=10, pady=10)
        # 数据输入框
        Connection_program.public_chat_entry = tk.Entry(Window_program.public_chat_room_frame, width=50, bd=3, font=("黑体", 15), fg="black", )
        Connection_program.public_chat_entry.grid(row=3, column=0, columnspan=2, padx=10, pady=10)
        # 消息发送按钮
        Connection_program.public_chat_send_button = tk.Button(Window_program.public_chat_room_frame, padx=10, pady=10, font=("黑体", 15), text="发送", fg="green", command=Connection_program.public_chat_send_function)
        Connection_program.public_chat_send_button.config(state="disabled")
        Connection_program.public_chat_send_button.grid(row=3, column=2, padx=10, pady=10)
        # 开启通信按钮
        Connection_program.public_chat_connect_start_button = tk.Button(Window_program.public_chat_room_frame, padx=10, pady=10, font=("黑体", 15), text="开启通信", fg="green", command=Connection_program.public_chat_room_connect_start_function)
        Connection_program.public_chat_connect_start_button.grid(row=4, column=0, padx=10, pady=10)
        # 结束通信按钮
        Connection_program.public_chat_connect_close_button = tk.Button(Window_program.public_chat_room_frame, padx=10, pady=10, font=("黑体", 15), text="结束通信", fg="red", command=Connection_program.public_chat_connect_close_function)
        Connection_program.public_chat_connect_close_button.config(state="disabled")
        Connection_program.public_chat_connect_close_button.grid(row=4, column=1, padx=10, pady=10)
        # 退出聊天室模式按钮
        Connection_program.public_chat_exit_button = tk.Button(Window_program.public_chat_room_frame, padx=10, pady=10, font=("黑体", 15), text="退出", fg="red", command=Connection_program.public_chat_room_window_to_interface_window)
        Connection_program.public_chat_exit_button.grid(row=4, column=2, padx=10, pady=10)

    # 由公共聊天室模式返回用户界面的方法
    @staticmethod
    def public_chat_room_window_to_interface_window():
        Window_program.public_chat_room_frame.destroy()
        Connection_program.interface_window()

    # 公共聊天室消息发送的方法
    @staticmethod
    def public_chat_send_function():
        if Connection_program.public_chat_connect_flag is True:
            # 消息发送预处理
            talk_data = Connection_program.public_chat_entry.get()  # 从消息输入框获得消息
            Connection_program.public_chat_entry.delete(0, "end")  # 清空消息输入框
            if talk_data != "":
                if talk_data == "@sever_public_chat_room_exit":
                    pass
                else:
                    talk_data = Main_program.name + ":" + talk_data + "\n"
                    Connection_program.login_socket.send(talk_data.encode())
                    # Connection_program.public_chat_text.insert("end", talk_data)

    # 定义加入公共聊天室的方法
    @staticmethod
    def public_chat_room_connect_start_function():
        data_socket = Connection_program.login_socket
        # 改变相关组件参数
        Connection_program.public_chat_connect_start_button.config(state="disabled")  # 截止本次通信结束，开启通信按钮失效
        Connection_program.public_chat_exit_button.config(state="disabled")  # 退出按钮失效
        Connection_program.public_chat_text.config(state="normal")
        # 向服务端发送请求加入聊天室的方法
        data_socket.send("@sever_public_chat_room_join".encode())
        # 接收来自服务端回复结果
        en_data = data_socket.recv(Connection_program.Max_data).decode()
        Connection_program.ready_text.config(state="normal")
        Connection_program.ready_text.delete("1.0", "end")
        if en_data == "OK":
            # 改变会话状态
            Connection_program.public_chat_connect_flag = True
            # print("已进入多人聊天室！")
            Connection_program.ready_text.insert("end", "已进入公共聊天室！")
            Connection_program.public_chat_text.insert("end", "已进入公共聊天室！\n")
            Connection_program.public_chat_connect_close_button.config(state="normal")  # 结束通信按钮生效
            Connection_program.public_chat_send_button.config(state="normal")  # 消息发送按钮生效
            # 创建在公共聊天室下的接收消息多线程
            th = threading.Thread(target=Connection_program.public_talk_recv, )
            th.start()  # 启用多线程
        else:
            # print("\033[91m进入多人聊天室失败\033[0m")
            Connection_program.ready_text.insert("end", "进入公共聊天室失败！")
            Connection_program.public_chat_text.insert("end", "进入公共聊天室失败！\n")
            Connection_program.public_chat_text.config(state="disabled")
            Connection_program.public_chat_exit_button.config(state="normal")  # 退出按钮生效
            Connection_program.public_chat_connect_start_button.config(state="normal")  # 通信开启按钮生效
        Connection_program.ready_text.config(state="disabled")

    # 结束公共聊天室通信的方法
    @staticmethod
    def public_chat_connect_close_function():
        if Connection_program.public_chat_connect_flag is True:
            Connection_program.login_socket.send("@sever_public_chat_room_exit".encode())  # 发送退出请求
            Connection_program.public_chat_connect_close_button.config(state="disabled")  # 结束通信按钮失效
            Connection_program.public_chat_send_button.config(state="disabled")  # 消息发送按钮失效

    # 定义接收公用聊天信息的方法
    @staticmethod
    def public_talk_recv():
        Connection_program.public_chat_text.insert("end", "已开始接收消息\n")
        while True:
            talk_data = Connection_program.login_socket.recv(Connection_program.Max_data).decode()
            if talk_data == "@client_public_chat_room_exit":
                Connection_program.public_chat_connect_flag = False
                Connection_program.public_chat_text.insert("end", "已退出公共聊天室！\n")
                Connection_program.public_chat_exit_button.config(state="normal")  # 退出按钮生效
                Connection_program.public_chat_connect_start_button.config(state="normal")  # 开启通信按钮生效
                Connection_program.public_chat_text.config(state="disabled")
                Connection_program.ready_text.config(state="normal")
                Connection_program.ready_text.delete("1.0", "end")
                Connection_program.ready_text.insert("end", "本次通信已结束")
                Connection_program.ready_text.config(state="disabled")
                break
            else:
                talk_data = talk_data + "\n"
                Connection_program.public_chat_text.insert("end", talk_data)

    # 用户查看自己公私钥对以及上传的方法
    @staticmethod
    def interface_key_window():
        # 初始设置参数
        Connection_program.interface_key_ready_flag = False
        # 设置窗口参数
        Window_program.interface_key_frame = tk.Frame(root_window, height=500, width=900, bd=3, padx=15, pady=10, )
        Window_program.interface_key_frame.place(anchor="center", relx=0.5, rely=0.5)

        # 窗口提示标签
        tk.Label(Window_program.interface_key_frame, fg="blue", font=("黑体", 15), padx=10, pady=5, text="用户 {} 的公私钥数据界面".format(Main_program.name)).grid(row=0, column=0, columnspan=3, padx=10, pady=10)
        # sm2公私钥对标签
        tk.Label(Window_program.interface_key_frame, height=1, width=20, fg="red", font=("黑体", 15), bd=3, padx=10, pady=5, text="用户SM2公私钥对:", ).grid(row=1, column=0, padx=10, pady=10)
        # sm2公钥展示框
        Connection_program.interface_key_sm2_text = tk.Text(Window_program.interface_key_frame, height=5, width=65, fg="black", font=("黑体", 10), bd=3, padx=10, pady=5, )
        Connection_program.interface_key_sm2_text.config(state="disabled")
        Connection_program.interface_key_sm2_text.grid(row=1, column=1, columnspan=2, padx=10, pady=10)

        # 身份公私钥对标签
        tk.Label(Window_program.interface_key_frame, height=1, width=20, fg="red", font=("黑体", 15), bd=3, padx=10, pady=5, text="用户身份公私钥对:", ).grid(row=2, column=0, padx=10, pady=10)
        # 身份公私钥对展示框
        Connection_program.interface_key_self_text = tk.Text(Window_program.interface_key_frame, height=5, width=65, fg="black", font=("黑体", 10), bd=3, padx=10, pady=5, )
        Connection_program.interface_key_self_text.config(state="disabled")
        Connection_program.interface_key_self_text.grid(row=2, column=1, columnspan=2, padx=10, pady=10)

        # 预共享公私钥对标签
        tk.Label(Window_program.interface_key_frame, height=1, width=20, fg="red", font=("黑体", 15), bd=3, padx=10, pady=5, text="用户预共享公私钥对:", ).grid(row=3, column=0, padx=10, pady=10)
        # 预共享公私钥对展示框
        Connection_program.interface_key_share_text = tk.Text(Window_program.interface_key_frame, height=5, width=65, fg="black", font=("黑体", 10), bd=3, padx=10, pady=5, )
        Connection_program.interface_key_share_text.config(state="disabled")
        Connection_program.interface_key_share_text.grid(row=3, column=1, columnspan=2, padx=10, pady=10)

        # 一次性公私钥对标签
        tk.Label(Window_program.interface_key_frame, height=1, width=20, fg="red", font=("黑体", 15), bd=3, padx=10, pady=5, text="用户一次性公私钥对:", ).grid(row=4, column=0, padx=10, pady=10)
        # 用户一次性公私钥对展示框
        Connection_program.interface_key_time_text = tk.Text(Window_program.interface_key_frame, height=15, width=65, fg="black", font=("黑体", 10), bd=3, padx=10, pady=5, )
        Connection_program.interface_key_time_text.config(state="disabled")
        Connection_program.interface_key_time_text.grid(row=4, column=1, columnspan=2, padx=10, pady=10)

        # 消息提示框
        Connection_program.ready_text = tk.Text(Window_program.interface_key_frame, height=1, width=70, fg="red", font=("黑体", 15), bd=3, padx=10, pady=5, )
        Connection_program.ready_text.config(state="disabled")
        Connection_program.ready_text.grid(row=5, column=0, columnspan=3, padx=10, pady=10)

        # 公私钥对生成按钮
        Connection_program.interface_key_born_button = tk.Button(Window_program.interface_key_frame, text="生成公私钥对", fg="green", font=("黑体", 15), anchor="center", padx=5, pady=5, command=Connection_program.interface_key_create_key)
        Connection_program.interface_key_born_button.config(state="disabled")
        Connection_program.interface_key_born_button.grid(row=6, column=0, padx=10, pady=10)

        # 公钥上传按钮
        Connection_program.interface_key_send_button = tk.Button(Window_program.interface_key_frame, text="上传公钥", fg="green", font=("黑体", 15), anchor="center", padx=5, pady=5, command=Connection_program.apply_hang_key)
        Connection_program.interface_key_send_button.config(state="disabled")
        Connection_program.interface_key_send_button.grid(row=6, column=1, padx=10, pady=10)

        # 退出按钮
        Connection_program.interface_key_exit_button = tk.Button(Window_program.interface_key_frame, text="退出", fg="red", font=("黑体", 15), anchor="center", padx=5, pady=5, command=Connection_program.interface_key_window_to_interface_window)
        Connection_program.interface_key_exit_button.grid(row=6, column=2, padx=10, pady=10)

        # 调用用户公私钥对获得的方法
        Connection_program.interface_key_get_client_all_key()

    # 获得用户公私钥对的二次方法
    @staticmethod
    def interface_key_get_client_all_key():
        # 修改组件参数
        Connection_program.ready_text.config(state="normal")
        Connection_program.ready_text.delete("1.0", "end")
        Connection_program.interface_key_sm2_text.config(state="normal")
        Connection_program.interface_key_self_text.config(state="normal")
        Connection_program.interface_key_share_text.config(state="normal")
        Connection_program.interface_key_time_text.config(state="normal")
        if File_program.get_client_all_key_data():
            # 录入并显示用户的sm2公私钥对
            Connection_program.interface_key_sm2_text.insert("end", "用户的SM2公钥为:")
            Connection_program.interface_key_sm2_text.insert("end", Crypto_program.self_sm2_public_key)
            Connection_program.interface_key_sm2_text.insert("end", "\n")
            Connection_program.interface_key_sm2_text.insert("end", "用户的SM2私钥为:")
            Connection_program.interface_key_sm2_text.insert("end", Crypto_program.self_sm2_private_key)
            # 录入并显示用户的身份公私钥对
            Connection_program.interface_key_self_text.insert("end", "用户的身份公钥为:")
            Connection_program.interface_key_self_text.insert("end", Crypto_program.self_public_key)
            Connection_program.interface_key_self_text.insert("end", "\n")
            Connection_program.interface_key_self_text.insert("end", "用户的身份私钥为:")
            Connection_program.interface_key_self_text.insert("end", Crypto_program.self_private_key)
            # 录入并显示用户的预共享公私钥对
            Connection_program.interface_key_share_text.insert("end", "用户的预共享公钥为:")
            Connection_program.interface_key_share_text.insert("end", Crypto_program.self_share_public_key)
            Connection_program.interface_key_share_text.insert("end", "\n")
            Connection_program.interface_key_share_text.insert("end", "用户的预共享私钥为:")
            Connection_program.interface_key_share_text.insert("end", Crypto_program.self_share_private_key)
            Connection_program.interface_key_share_text.insert("end", "\n")
            Connection_program.interface_key_share_text.insert("end", "用户的预共享公钥的签名为:")
            Connection_program.interface_key_share_text.insert("end", Crypto_program.self_share_public_key_sign)
            # 录入并显示用户的一次性公私钥对
            key_num = len(Crypto_program.self_time_key_list)
            for i in range(0, int(key_num/2 - 1), 2):
                Connection_program.interface_key_time_text.insert("end", "用户的一次性公钥为:")
                Connection_program.interface_key_time_text.insert("end", Crypto_program.self_time_key_list[i])
                Connection_program.interface_key_time_text.insert("end", "\n")
                Connection_program.interface_key_time_text.insert("end", "用户的一次性私钥为:")
                Connection_program.interface_key_time_text.insert("end", Crypto_program.self_time_key_list[i+1])
                Connection_program.interface_key_time_text.insert("end", "\n")
            Connection_program.interface_key_send_button.config(state="normal")  # 上传公钥按钮生效
            Connection_program.ready_text.insert("end", "用户公私钥对数据获取完成！")
        else:
            Connection_program.ready_text.insert("end", "您当前暂无公私钥对！")
            Connection_program.interface_key_born_button.config(state="normal")  # 公私钥对生成按钮生效
        Connection_program.ready_text.config(state="disabled")
        Connection_program.interface_key_sm2_text.config(state="disabled")
        Connection_program.interface_key_self_text.config(state="disabled")
        Connection_program.interface_key_share_text.config(state="disabled")
        Connection_program.interface_key_time_text.config(state="disabled")

    # 由查看公私钥对及上传窗口 返回 用户窗口的方法
    @staticmethod
    def interface_key_window_to_interface_window():
        Window_program.interface_key_frame.destroy()
        Connection_program.interface_window()

    # 用户公私钥数据生成的方法
    @staticmethod
    def interface_key_create_key():
        Connection_program.interface_key_born_button.config(state="disabled")  # 生成公私钥对按钮失效
        Connection_program.interface_key_exit_button.config(state="disabled")  # 退出按钮失效
        if File_program.get_client_all_key_data():
            pass
        else:
            # 调用用户公私钥数据文件生成的方法
            Crypto_program.create_client_key()
            # 再次显示用户公私钥数据
            Connection_program.interface_key_get_client_all_key()
        Connection_program.interface_key_send_button.config(state="normal")  # 上传公私钥对按钮生效
        Connection_program.interface_key_exit_button.config(state="normal")  # 退出按钮失效

    # 定义用户向服务端请求挂载公钥的方法
    @staticmethod
    def apply_hang_key():
        Connection_program.interface_key_send_button.config(state="disabled")  # 公钥上传按钮失效
        Connection_program.interface_key_exit_button.config(state="disabled")  # 退出按钮失效
        data_socket = Connection_program.login_socket
        # print("正在挂载公钥中...")
        Connection_program.ready_text.config(state="normal")
        Connection_program.ready_text.delete("1.0", "end")
        Connection_program.ready_text.insert("end", "正在上传公钥中...")
        Connection_program.ready_text.config(state="disabled")
        # 发送请求挂载公钥指令
        data_socket.send("@sever_hang_key".encode())
        # 调用初始化获得用户公私钥数据的方法
        if File_program.get_client_all_key_data():  # 判断该用户的公私钥对数据文件是否存在
            pass
        else:
            Crypto_program.create_client_key(1)  # 调用相关方法重建该用户的公私钥对数据文件
            File_program.get_client_all_key_data()  # 再次调用获得用户公私钥对
        data_socket.send(str(Crypto_program.self_sm2_public_key).encode())  # 发送用户SM2公钥
        time.sleep(0.1)  # 延迟，防止粘包
        data_socket.send(str(Crypto_program.self_public_key).encode())  # 发送身份公钥
        time.sleep(0.1)  # 延迟，防止粘包
        data_socket.send(str(Crypto_program.self_share_public_key).encode())  # 发送预共享公钥
        time.sleep(0.1)  # 延迟，防止粘包
        data_socket.send(str(Crypto_program.self_share_public_key_sign).encode())  # 发送预共享公钥的签名
        time.sleep(0.1)  # 延迟，防止粘包
        for item in range(0, len(Crypto_program.self_time_key_list)):  # 遍历发送一次性公钥
            time.sleep(0.1)  # 延迟，防止粘包
            if item % 2 != 0:  # 间隔发送，确保发送的是用户的一次性公钥
                continue
            else:
                data_socket.send(str(Crypto_program.self_time_key_list[item]).encode())
        time.sleep(0.1)  # 延迟，防止粘包
        data_socket.send("@sever_key_end".encode())  # 发送公钥发送完毕提示消息
        end_flag = data_socket.recv(Connection_program.Max_data).decode()  # 接收来自服务端的完成消息
        Connection_program.ready_text.config(state="normal")
        Connection_program.ready_text.delete("1.0", "end")
        if end_flag == "OK":
            # print("公钥上传成功!")
            Connection_program.ready_text.insert("end", "公钥上传成功！")
        else:
            # print("\033[91m公钥上传失败！\033[0m")
            Connection_program.ready_text.insert("end", "公钥上传失败！")
        Connection_program.ready_text.config(state="disabled")
        Connection_program.interface_key_exit_button.config(state="normal")  # 退出按钮生效

    # 服务端公钥及获得公钥展示界面窗口
    @staticmethod
    def show_sever_key_window():
        # 初始设置
        Connection_program.get_key_flag = False
        Connection_program.get_key_into_flag = False
        # 初始设置所需变量
        Connection_program.get_key_num = tk.StringVar()
        # 设置容器
        Window_program.show_sever_key_frame = tk.Frame(root_window, height=500, width=900, bd=3, padx=15, pady=10)
        Window_program.show_sever_key_frame.place(anchor="center", relx=0.5, rely=0.5)

        # 窗口提示标签
        tk.Label(Window_program.show_sever_key_frame, fg="blue", font=("黑体", 15), padx=10, pady=5, text="获得公钥数据界面").grid(row=0, column=0, columnspan=3, padx=10, pady=10)

        # 纵向1
        # 服务端公钥用户名标签
        tk.Label(Window_program.show_sever_key_frame, height=1, width=20, fg="red", font=("黑体", 15), bd=3, padx=10, pady=5, text="当前可获得公钥的用户名").grid(row=1, column=0, padx=10, pady=10)
        # 服务端公钥用户名栏
        Connection_program.show_sever_key_name_text = tk.Text(Window_program.show_sever_key_frame, height=20, width=20, bd=3, font=("黑体", 15), fg="black", padx=10, pady=5)
        Connection_program.show_sever_key_name_text.grid(row=2, rowspan=4, column=0, padx=10, pady=10)
        Connection_program.show_sever_key_name_text.config(state="disabled")
        # 消息提示栏
        Connection_program.ready_text = tk.Text(Window_program.show_sever_key_frame, height=2, width=20, bd=3, font=("黑体", 15), fg="red", padx=10, pady=5)
        Connection_program.ready_text.grid(row=6, column=0, padx=10, pady=10)
        Connection_program.ready_text.config(state="disabled")

        # 纵向2
        # 客户端获得公钥标签
        tk.Label(Window_program.show_sever_key_frame,  height=1, width=40, fg="red", font=("黑体", 15), bd=3, padx=10, pady=5, text="公钥计算及结果显示").grid(row=1, column=1, columnspan=2, padx=10, pady=10)
        # 客户端获得公钥计算及结果栏
        Connection_program.show_sever_key_get_text = tk.Text(Window_program.show_sever_key_frame, width=60, height=15, bd=3, font=("黑体", 10), fg="red", padx=10, pady=5)
        Connection_program.show_sever_key_get_text.grid(row=2, column=1, columnspan=2, padx=10, pady=10)
        Connection_program.show_sever_key_get_text.config(state="disabled")
        # 提示标签
        tk.Label(Window_program.show_sever_key_frame,  height=2, width=30, bd=3,  text="请输入目标用户序号以获取公钥", fg="black", font=("黑体", 15), anchor="center", padx=5, pady=5, ).grid(row=3, column=1, columnspan=2,  padx=10, pady=10)
        # 输入序号栏
        tk.Entry(Window_program.show_sever_key_frame, width=10,  font=("黑体", 15), fg="red", textvariable=Connection_program.get_key_num).grid(row=4, column=1, padx=10, pady=10)
        # 输入确定按钮
        Connection_program.get_key_num_button = tk.Button(Window_program.show_sever_key_frame, height=1, width=10,  text="确定", fg="red", font=("黑体", 15), anchor="center", padx=5, pady=5, command=Connection_program.get_hang_key)
        Connection_program.get_key_num_button.grid(row=4, column=2, padx=10, pady=10)
        # 最终获得X3DH协商密钥标签
        tk.Label(Window_program.show_sever_key_frame, height=2, width=20, bd=3,  text="X3DH协商密钥为:", fg="blue", font=("黑体", 15), anchor="center", padx=5, pady=5, ).grid(row=5, column=1, padx=10, pady=10)
        # 最终获得X3DH协商密钥输出栏
        Connection_program.output_x3dh_key_text = tk.Text(Window_program.show_sever_key_frame, height=3, width=20, bd=3, font=("黑体", 15), fg="red", padx=10, pady=5)
        Connection_program.output_x3dh_key_text.grid(row=5, column=2, padx=10, pady=10)
        # 获得公钥按钮
        Connection_program.get_key_button = tk.Button(Window_program.show_sever_key_frame,  text="获取公钥", fg="green", font=("黑体", 15), anchor="center", padx=5, pady=5, command=Connection_program.search_hang_key)
        Connection_program.get_key_button.grid(row=6, column=1, padx=10, pady=10)
        # 退出按钮
        tk.Button(Window_program.show_sever_key_frame,  text="退出", fg="red", font=("黑体", 15), anchor="center", padx=5, pady=5, command=Connection_program.show_sever_key_window_to_interface_window).grid(row=6, column=2, padx=10, pady=10)

    # 服务端公钥及获得公钥展示界面 转向 用户界面
    @staticmethod
    def show_sever_key_window_to_interface_window():
        if Connection_program.get_key_flag is True:  # 判断用户是否发送了公钥获取请求
            Connection_program.login_socket.send("@sever_get_client_key_exit".encode())
        Window_program.show_sever_key_frame.destroy()
        Connection_program.interface_window()

    # 定义查询服务端已挂载公钥情况以及获取的方法
    @staticmethod
    def search_hang_key():
        # 成功获取用户公钥数据后，本次界面下获取公钥数据按钮不再生效
        Connection_program.get_key_button.config(state="disabled")
        Connection_program.get_key_into_flag = True
        data_socket = Connection_program.login_socket
        # 初始化读取用户已获得的公钥数据
        if File_program.get_client_get_key_list_file(Main_program.name):
            pass
        else:
            # print("\033[91m用户数据读取异常\033[0m")
            Connection_program.ready_text.config(state="normal")
            Connection_program.ready_text.delete("1.0", "end")
            Connection_program.ready_text.insert("end", "用户数据读取异常！")
        data_socket.send("@sever_get_key".encode())  # 向服务端发送查询已挂载公钥的请求指令
        Connection_program.get_key_flag = True  # 一旦发送请求，改变状态
        ready_flag = data_socket.recv(Connection_program.Max_data).decode()  # 接收来自服务端的准备信息
        if ready_flag == "OK":  # 判断服务端回应
            pass_flag = True
        else:
            # print("\033[91m当前服务端不存在已挂载公钥！\033[0m")
            Connection_program.show_sever_key_name_text.config(state="normal")
            Connection_program.show_sever_key_name_text.delete("1.0", "end")
            Connection_program.show_sever_key_name_text.insert("end", "当前服务端不存在已挂载公钥!")
            Connection_program.show_sever_key_name_text.config(state="disabled")
            pass_flag = False
        if pass_flag is True:  # 判断接下来是否继续执行
            Connection_program.show_sever_key_name_text.config(state="normal")
            Connection_program.show_sever_key_name_text.delete("1.0", "end")
            hang_key_num = data_socket.recv(Connection_program.Max_data).decode()  # 接收来自服务端的已挂载公钥数量
            hang_key_num = int(hang_key_num)
            if hang_key_num <= 0:
                # print("\033[91m数据异常！\033[0m")
                Connection_program.show_sever_key_name_text.insert("end", "数据异常！")
            else:
                # print("当前服务端已挂载公钥的用户数量为:{}".format(hang_key_num))
                Connection_program.show_sever_key_name_text.insert("end", "当前服务端已挂载公钥的用户数量为:{}\n".format(hang_key_num))
                Connection_program.hang_key_person_list.clear()  # 清空列表 防止重复
                for item in range(0, hang_key_num):  # 依次接受来自服务端的已挂载公钥的用户名列表
                    name = data_socket.recv(Connection_program.Max_data).decode()  # 接收来自服务端的已挂载公钥的用户名
                    Connection_program.hang_key_person_list.append(name)  # 将用户名添加至可通信用户列表
            end_flag = data_socket.recv(Connection_program.Max_data).decode()  # 接收结束校验数据
            if end_flag == "@client_name_end":
                # 展示服务端已挂载公钥的用户
                # print("服务端已挂载公钥的用户有:")
                num_list = 1
                for name in Connection_program.hang_key_person_list:
                    # print(str(num_list), " ", name)
                    Connection_program.show_sever_key_name_text.insert("end", "{} {}\n".format(num_list, name))
                    num_list += 1
                Connection_program.show_sever_key_name_text.config(state="disabled")
                # print("输入对应用户序号以获得对应的公钥数据，或者输入(退出)")
                Connection_program.ready_text.config(state="normal")
                Connection_program.ready_text.delete("1.0", "end")
                Connection_program.ready_text.insert("end", "获取公钥挂载状况数据成功！")
                Connection_program.ready_text.config(state="disabled")

    # 获取用户公钥的具体对应的方法
    @staticmethod
    def get_hang_key():
        # 请求发送预处理
        choose_num = Connection_program.get_key_num.get()
        data_socket = Connection_program.login_socket
        num_list = len(Connection_program.hang_key_person_list)
        Connection_program.ready_text.config(state="normal")
        Connection_program.ready_text.delete("1.0", "end")
        if Connection_program.get_key_into_flag is True:
            if choose_num.isdigit():
                choose_num = int(choose_num)  # 格式转换
                if choose_num in range(1, num_list+1):
                    choose_name = Connection_program.hang_key_person_list[int(choose_num) - 1]
                    if choose_name in Crypto_program.other_get_key_name_list:
                        # print("\033[91m您已经获得过该用户的公钥了！\033[0m")
                        Connection_program.ready_text.insert("end", "你已经获得过该用户的公钥了！")
                    elif choose_name == Main_program.name:
                        # print("\033[91m您不能获取自己的公钥！\033[0m")
                        Connection_program.ready_text.insert("end", "您不能获得自己的公钥！")
                    else:
                        Connection_program.show_sever_key_get_text.config(state="normal")
                        # 向服务端发送请求获得用户数据的指令
                        data_socket.send("@sever_get_client_key".encode())
                        Connection_program.get_key_flag = False
                        time.sleep(0.1)  # 延迟，防止粘包
                        data_socket.send(choose_name.encode())  # 发送选择的用户名
                        next_flag = data_socket.recv(Connection_program.Max_data).decode()
                        if next_flag == "OK":
                            # 本次获取公钥，若成功则获取用户公钥按钮不再生效
                            Connection_program.get_key_num_button.config(state="disabled")
                            # print("获取公钥数据中...")
                            Connection_program.show_sever_key_get_text.insert("end", "获取公钥数据中\n")
                            other_sm2_public_key = data_socket.recv(Connection_program.Max_data).decode()
                            # print("对方SM2公钥为:{}".format(other_sm2_public_key))
                            Connection_program.show_sever_key_get_text.insert("end", "对方SM2公钥为:{}\n".format(other_sm2_public_key))
                            other_public_key = data_socket.recv(Connection_program.Max_data).decode()
                            # print("对方身份公钥为:{}".format(other_public_key))
                            Connection_program.show_sever_key_get_text.insert("end", "对方身份公钥为:{}\n".format(other_public_key))
                            other_share_public_key = data_socket.recv(Connection_program.Max_data).decode()
                            # print("对方预共享公钥为:{}".format(other_share_public_key))
                            Connection_program.show_sever_key_get_text.insert("end", "对方预共享公钥为:{}\n".format(other_share_public_key))
                            other_share_public_key_sign = data_socket.recv(Connection_program.Max_data).decode()
                            # print("对方预共享公钥签名为:{}".format(other_share_public_key_sign))
                            Connection_program.show_sever_key_get_text.insert("end", "对方预共享公钥签名为:{}\n".format(other_share_public_key_sign))
                            other_time_public_key = data_socket.recv(Connection_program.Max_data).decode()
                            # print("对方一次性公钥为：{}".format(other_time_public_key))
                            Connection_program.show_sever_key_get_text.insert("end", "对方一次性公钥为:{}\n".format(other_time_public_key))
                            # print("正在进行 X3DH 协议下的计算...")
                            Connection_program.show_sever_key_get_text.insert("end", "正在进行 X3DH 协议下的计算...\n")
                            # 调用 x3dh 的方法
                            ok_flag, connect_key, time_public_key = Crypto_program.x3dh_active_create(choose_name, other_sm2_public_key, other_public_key, other_share_public_key, other_share_public_key_sign, other_time_public_key)
                            if ok_flag is True:  # 判断计算结果
                                # print("计算获得的密钥为:{}".format(connect_key))
                                Connection_program.show_sever_key_get_text.insert("end", "计算获得的协商密钥为:{}\n".format(connect_key))
                                Connection_program.output_x3dh_key_text.delete("1.0", "end")
                                Connection_program.output_x3dh_key_text.insert("end", connect_key)
                                # print("使用的临时私钥对应的公钥为:{}".format(time_public_key))
                                Connection_program.show_sever_key_get_text.insert("end", "使用的临时私钥对应的公钥为:{}\n".format(time_public_key))
                                # 调用用户已获得公钥数据文件对计算结果进行保存
                                if File_program.update_client_get_key_list_file(1, Main_program.name, choose_name, other_time_public_key, connect_key, time_public_key):
                                    # print("计算结果及对应用户数据保存成功")
                                    Connection_program.show_sever_key_get_text.insert("end", "计算结果及对应用户数据保存成功！\n")
                                    Connection_program.ready_text.insert("end", "与用户 {} 的X3DH协商密钥计算成功！".format(choose_name))
                                else:
                                    # print("\033[91m计算结果及对应用户数据保存失败！\033[0m")
                                    Connection_program.show_sever_key_get_text.insert("end", "计算结果及对应用户数据保存失败！\n")
                            else:
                                # print("\033[91m计算失败\033[0m")
                                Connection_program.show_sever_key_get_text.insert("end", "计算失败\n")
                        else:
                            # print("\033[91m服务端数据异常\033[0m")
                            Connection_program.ready_text.insert("end", "服务端数据异常")
                else:
                    # print("\033[91m请输入正确的用户序号\033[0m")
                    Connection_program.ready_text.insert("end", "请输入正确的用户序号！")
            else:
                Connection_program.ready_text.insert("end", "请输入目标用户的序号！")
            Connection_program.show_sever_key_get_text.config(state="disabled")
            Connection_program.ready_text.config(state="disabled")
        else:
            Connection_program.ready_text.config(state="normal")
            Connection_program.ready_text.delete("1.0", "end")
            Connection_program.ready_text.insert("end", "您当前暂未请求获取公钥数据！")
            Connection_program.ready_text.config(state="disabled")

    # 展示用户已获得公钥数据的窗口  同时也是连接指定用户通信的窗口
    @staticmethod
    def show_client_key_window():
        # 初始设置相关参数
        Connection_program.show_client_key_connect_flag = False
        # 设置窗口参数
        Window_program.show_client_key_frame = tk.Frame(root_window, height=500, width=950, bd=3, padx=15, pady=10)
        Window_program.show_client_key_frame.place(anchor="center", relx=0.5, rely=0.5)
        # 窗口提示标签
        tk.Label(Window_program.show_client_key_frame, fg="blue", font=("黑体", 15), padx=10, pady=5, text="用户 {} 已获得公钥数据界面".format(Main_program.name)).grid(row=0, column=0, columnspan=3, padx=10, pady=10)
        # 数据展示文本框
        Connection_program.show_client_key_text = tk.Text(Window_program.show_client_key_frame, height=30, width=100, bd=3, font=("黑体", 10), fg="black", padx=10, pady=10)
        Connection_program.show_client_key_text.config(state="disabled")
        Connection_program.show_client_key_text.grid(row=1, column=0, columnspan=3, padx=10, pady=10)
        # 消息提示框
        Connection_program.ready_text = tk.Text(Window_program.show_client_key_frame, height=3, width=45, bd=3, font=("黑体", 15), fg="red", padx=10, pady=10)
        Connection_program.ready_text.config(state="disabled")
        Connection_program.ready_text.grid(row=2, column=0, columnspan=2, padx=10, pady=10)
        # 模式显示框
        Connection_program.show_client_key_mode_text = tk.Text(Window_program.show_client_key_frame, height=3, width=15, bd=3, font=("黑体", 15), fg="red", padx=10, pady=10)
        Connection_program.show_client_key_mode_text.insert("end", "数据显示模式")
        Connection_program.show_client_key_mode_text.config(state="disabled")
        Connection_program.show_client_key_mode_text.grid(row=2, column=2, padx=10, pady=10)
        # 数据输入框
        Connection_program.show_client_key_entry = tk.Entry(Window_program.show_client_key_frame, width=47, bd=3, font=("黑体", 15), fg="black", )
        Connection_program.show_client_key_entry.grid(row=3, column=0, columnspan=2, padx=10, pady=10)
        # 数据发送按钮
        Connection_program.show_client_key_input_button = tk.Button(Window_program.show_client_key_frame, padx=10, pady=10, font=("黑体", 15), text="发送", fg="green", command=Connection_program.show_client_key_send_function)
        Connection_program.show_client_key_input_button.config(state="disabled")
        Connection_program.show_client_key_input_button.grid(row=3, column=2, padx=10, pady=10)
        # 开启通信按钮
        Connection_program.show_client_key_connect_start_button = tk.Button(Window_program.show_client_key_frame, padx=10, pady=10, font=("黑体", 15), text="开启通信", fg="green", command=Connection_program.connect_target_client)
        Connection_program.show_client_key_connect_start_button.grid(row=4, column=0, padx=10, pady=10)
        # 结束通信按钮
        Connection_program.show_client_key_connect_close_button = tk.Button(Window_program.show_client_key_frame, padx=10, pady=10, font=("黑体", 15), text="结束通信", fg="red", command=Connection_program.show_client_key_connect_end_function)
        Connection_program.show_client_key_connect_close_button.config(state="disabled")
        Connection_program.show_client_key_connect_close_button.grid(row=4, column=1, padx=10, pady=10)
        # 退出按钮
        Connection_program.show_client_key_exit_button = tk.Button(Window_program.show_client_key_frame, padx=10, pady=10, font=("黑体", 15), text="退出", fg="red", command=Connection_program.show_client_key_window_to_interface_window)
        Connection_program.show_client_key_exit_button.grid(row=4, column=2, padx=10, pady=10)

        # 调用用户数据读取的方法
        Connection_program.browse_key()

    # 由公钥显示界面 转向 用户界面的方法
    @staticmethod
    def show_client_key_window_to_interface_window():
        if Connection_program.show_client_key_connect_flag is False:  # 判断当前是否处于通信状态
            Window_program.show_client_key_frame.destroy()
            Connection_program.interface_window()
        else:
            Connection_program.ready_text.config(state="normal")
            Connection_program.ready_text.delete("1.0", "end")
            Connection_program.ready_text.insert("end", "您当前处于通信状态，无法直接退出！")
            Connection_program.ready_text.config(state="disabled")

    # 定义用户查看当前已获得公钥数据的方法
    @staticmethod
    def browse_key():
        Connection_program.ready_text.config(state="normal")
        Connection_program.ready_text.delete("1.0", "end")
        Connection_program.show_client_key_text.config(state="normal")
        # print("正在读取用户数据中...")
        Connection_program.show_client_key_text.insert("end", "正在读取用户数据中...\n")
        if File_program.get_client_get_key_list_file(Main_program.name):
            # print("当前已获得的公钥数据如下:")
            Connection_program.show_client_key_text.insert("end", "当前已获得公钥数据如下:\n")
            data_num = len(Crypto_program.other_get_key_name_list)
            if data_num > 0:
                for i in range(0, data_num):
                    # print(i, "用户名:", Crypto_program.other_get_key_name_list[i])
                    Connection_program.show_client_key_text.insert("end", "{} 用户名: {}\n".format(i, Crypto_program.other_get_key_name_list[i]))
                    # print(i, "用户一次性公钥:", Crypto_program.other_get_time_key_list[i])
                    Connection_program.show_client_key_text.insert("end", "{} 用户一次性公钥: {}\n".format(i, Crypto_program.other_get_time_key_list[i]))
                    # print(i, "基于 X3DH 生成的密钥:", Crypto_program.other_get_x3dh_key_list[i])
                    Connection_program.show_client_key_text.insert("end", "{} 基于 X3DH 生成的协商密钥: {}\n".format(i, Crypto_program.other_get_x3dh_key_list[i]))
                    # print(i, "自己对应使用的一次性公钥:", Crypto_program.self_get_x3dh_time_key_list[i])
                    Connection_program.show_client_key_text.insert("end", "{} 自己使用的临时公钥: {}\n".format(i, Crypto_program.self_get_x3dh_time_key_list[i]))
                    Connection_program.show_client_key_text.insert("end", "\n---------------------------------\n\n")
                # print("请选择通信对象(输入对应序号，或者输入“退出”)")
                Connection_program.ready_text.insert("end", "若想联系目标用户，请输入对应序号后，点击下方“开启通信”按钮")
            else:
                Connection_program.show_client_key_text.insert("end", "哎呀，当前暂无已获得的公钥数据\n")
                # print("哎呀，当前暂无已获得的公钥数据")
        else:
            # print("\033[91m用户数据读取失败！\033[0m")
            Connection_program.ready_text.insert("end", "用户数据读取失败！")
        Connection_program.ready_text.config(state="disabled")
        Connection_program.show_client_key_text.config(state="disabled")
        Connection_program.show_client_key_input_button.config(state="normal")

    # 连接目标用户的与检测方法
    @staticmethod
    def connect_target_client():
        # 发送请求预处理
        Connection_program.show_client_key_connect_start_button.config(state="disabled")  # 截止本次通信完成，开启通信按钮失效
        choose_num = Connection_program.show_client_key_entry.get()
        Connection_program.ready_text.config(state="normal")
        Connection_program.ready_text.delete("1.0", "end")
        data_num = len(Crypto_program.other_get_key_name_list)
        if choose_num.isdigit():
            choose_num = int(choose_num)
            if choose_num in range(0, data_num):
                choose_name = Crypto_program.other_get_key_name_list[int(choose_num)]  # 选择的用户名
                choose_time_key = Crypto_program.other_get_time_key_list[int(choose_num)]  # 选择用户的 一次性公钥
                choose_x3dh_key = Crypto_program.other_get_x3dh_key_list[int(choose_num)]  # 基于该用户获得的X3DH密钥
                choose_self_time_key = Crypto_program.self_get_x3dh_time_key_list[int(choose_num)]  # 自己对应使用的一次性公钥
                # 调用客户端发起指定用户连接的方法
                Connection_program.client_x3dh_connect(choose_name, choose_time_key, choose_x3dh_key, choose_self_time_key)
            else:
                # print("\033[91m请输入正确的用户序号！\033[0m")
                Connection_program.ready_text.insert("end", "请输入正确的用户序号！")
                Connection_program.show_client_key_connect_start_button.config(state="normal")
        else:
            # print("\033[91m请输入正确的操作数据！\033[0m")
            Connection_program.ready_text.insert("end", "请输入正确的正确的操作数据！")
            Connection_program.show_client_key_connect_start_button.config(state="normal")
        Connection_program.ready_text.config(state="disabled")

    # 定义进行X3DH协议下通信的方法  (等同于等待模式 被动态)
    @staticmethod
    def client_x3dh_connect(other_name, other_time_public_key, x3dh_key, self_time_public_key):
        # 改变窗口内部分组件的参数
        Connection_program.show_client_key_text.config(state="normal")
        Connection_program.show_client_key_text.delete("1.0", "end")
        Connection_program.ready_text.config(state="normal")
        Connection_program.ready_text.delete("1.0", "end")
        Connection_program.show_client_key_connect_flag = True  # 改变通信状态
        # 开启通信
        data_socket = Connection_program.login_socket
        Connection_program.client_wait_mode_x3dh_key = x3dh_key
        # print("正在向服务端发送查询请求中...")
        Connection_program.show_client_key_text.insert("end", "正在向服务端发送查询请求中...\n")
        data_socket.send("@sever_connect_target_client".encode())  # 向服务器发送指定用户连接请求
        result_flag = data_socket.recv(Connection_program.Max_data).decode()
        if result_flag == "OK":  # 判断回复
            # print("服务端已接收请求，正在发送请求的用户名:{}".format(other_name))
            Connection_program.show_client_key_text.insert("end", "服务端已接收请求，正在发送请求的用户名:{}\n".format(other_name))
            data_socket.send(other_name.encode())
            result_flag = data_socket.recv(Connection_program.Max_data).decode()
            if result_flag == "OK":  # 判断目标用户是否出于等待模式
                # print("当前目标用户:{}，处于等待模式".format(other_name))
                Connection_program.show_client_key_text.insert("end", "当前目标用户:{}, 处于等待状态\n".format(other_name))
                # print("当前使用的对方用户一次性公钥为：{}".format(other_time_public_key))
                Connection_program.show_client_key_text.insert("end", "当前使用的对方的一次性公钥为:{}\n".format(other_time_public_key))
                # print("当前使用的X3DH密钥:{}".format(x3dh_key))
                Connection_program.show_client_key_text.insert("end", "当前使用的X3DH协商密钥为:{}\n".format(x3dh_key))
                # print("当前自己使用的临时公钥为:{}".format(self_time_public_key))
                Connection_program.show_client_key_text.insert("end", "当前自己使用的临时公钥为:{}\n".format(self_time_public_key))
                # print("正在等待目标用户回复中...")
                Connection_program.show_client_key_text.insert("end", "正在等待目标用户回复中...\n")
                flag = data_socket.recv(Connection_program.Max_data).decode()
                if flag == "OK":  # 判断对方用户回复结果
                    # 初始获得自己的公钥
                    File_program.get_client_all_key_data()
                    data_socket.send("OK".encode())
                    # print("用户 {} 同意了请求".format(other_name))
                    Connection_program.show_client_key_text.insert("end", "用户 {} 同意了通信请求\n".format(other_name))
                    # print("正在进行 X3DH 数据的发送")
                    Connection_program.show_client_key_text.insert("end", "正在进行 X3DH 所需数据的发送\n")
                    # 发送自己使用的对方的一次性公钥
                    data_socket.send(str(other_time_public_key).encode())
                    time.sleep(0.1)  # 时延，防止粘包
                    # print("已发送使用的对方的一次性公钥")
                    Connection_program.show_client_key_text.insert("end", "已发送使用的对方的一次性公钥\n")
                    # 发送自己的身份公钥
                    data_socket.send(str(Crypto_program.self_public_key).encode())
                    time.sleep(0.1)
                    # print("已发送自己的身份公钥")
                    Connection_program.show_client_key_text.insert("end", "已发送自己的公钥\n")
                    # 发送自己使用的临时公钥
                    data_socket.send(str(self_time_public_key).encode())
                    # print("已发送自己使用的临时公钥,正在等待对方计算完成...")
                    Connection_program.show_client_key_text.insert("end", "已发送自己使用的临时公钥，正在等待对方计算完成...\n")
                    # 接收对方完成计算的信号
                    ensure_data = data_socket.recv(Connection_program.Max_data).decode()
                    if ensure_data == "OK":
                        data_socket.send("OK".encode())
                        # print("对方已完成计算，正在进行验证...")
                        Connection_program.show_client_key_text.insert("end", "对方已完成计算，正在进行验证...\n")
                        # 生成验证消息
                        ensure_data = Crypto_program.random_key_born(20)  # 默认 20 位随机验证消息
                        # print("已生成随机验证消息:{}".format(ensure_data))
                        Connection_program.show_client_key_text.insert("end", "已生成随机验证消息:{}\n".format(ensure_data))
                        en_ensure_data = pysm4.encrypt_ecb(ensure_data, x3dh_key[0:15])
                        # print("使用 X3DH 密钥加密后为: {}".format(en_ensure_data))
                        Connection_program.show_client_key_text.insert("end", "使用 X3DH 密钥加密后为:{}\n".format(en_ensure_data))
                        data_socket.send(en_ensure_data.encode())
                        # print("已发送加密后的验证消息，等待对方的解密回复中...")
                        Connection_program.show_client_key_text.insert("end", "已发送加密后的验证消息，等待对方的解密回复中...\n")
                        # 接收对方的解密结果
                        other_data = data_socket.recv(Connection_program.Max_data).decode()
                        # print("已接收到对方解密结果:{}".format(other_data))
                        Connection_program.show_client_key_text.insert("end", "已接收到对方的解密结果:{}\n".format(other_data))
                        if other_data == ensure_data:
                            # print("对方验证通过")
                            Connection_program.show_client_key_text.insert("end", "对方验证通过\n")
                            data_socket.send("OK".encode())
                            # 改变通信连接状态
                            Connection_program.client_wait_mode_connect_flag = True
                            # 初始设置KDF，DH棘轮
                            File_program.init_x3dh_p_g()
                            Crypto_program.kdf_dh_self_time_private_key = Crypto_program.self_private_key  # 私钥设置为自己身份公钥的私钥
                            Crypto_program.kdf_chain_random_data = Connection_program.client_wait_mode_x3dh_key  # X3DH协商密钥为初始root key
                            kdf_dh_other_time_public_key = data_socket.recv(Connection_program.Max_data).decode()  # 接收对方初始的临时公钥
                            test_data = data_socket.recv(Connection_program.Max_data).decode()
                            Crypto_program.kdf_dh_other_new_time_public_key = kdf_dh_other_time_public_key
                            Crypto_program.kdf_dh_decry_function(test_data)
                            # 创建接收多线程
                            th = threading.Thread(target=Connection_program.create_wait_passive_accept, args=(data_socket, other_name,))
                            th.start()
                            Connection_program.ready_text.insert("end", "通信已就绪，可以开始发送消息！")
                            Connection_program.show_client_key_mode_text.config(state="normal")
                            Connection_program.show_client_key_mode_text.delete("1.0", "end")
                            Connection_program.show_client_key_mode_text.insert("end", "通信模式")
                            Connection_program.show_client_key_mode_text.config(state="disabled")
                            Connection_program.show_client_key_connect_close_button.config(state="normal")  # 结束通信按钮生效
                            Connection_program.show_client_key_exit_button.config(state="disabled")  # 退出按钮失效
                            """
                            while True:
                                talk_data = input()
                                if Connection_program.client_wait_mode_connect_flag is False:
                                    data_socket.send("@sever_wait_mode_passive_this_connect_end".encode())
                                    print(other_name, "您被中断通信，已结束本次通信")
                                    break
                                else:
                                    if talk_data == "exit" or talk_data == "退出" or talk_data == "@sever_wait_mode_this_connect_end":  # 判断是否主动中断通信
                                        data_socket.send("@sever_wait_mode_active_this_connect_end".encode())
                                        Connection_program.client_wait_mode_connect_flag = False
                                        break
                                    else:
                                        # 在此处加入双棘轮算法
                                        talk_data = Crypto_program.kdf_dh_encry_function(talk_data)
                                        data_socket.send(talk_data.encode())
                                        time.sleep(0.1)
                                        data_socket.send(str(Crypto_program.kdf_dh_self_time_public_key).encode())
                            """
                        else:
                            # print("\033[91m对方验证失败\033[0m")
                            Connection_program.show_client_key_text.insert("end", "对方验证失败！\n")
                            data_socket.send("NO".encode())
                            Connection_program.show_client_key_connect_flag = False
                    else:
                        data_socket.send("NO".encode())
                        # print("对方计算失败，已自动退出")
                        Connection_program.show_client_key_text.insert("end", "对方计算失败\n")
                        Connection_program.show_client_key_connect_flag = False
                else:
                    data_socket.send("NO".encode())
                    # print("用户 {} 拒绝了请求".format(other_name))
                    Connection_program.show_client_key_text.insert("end", "目标用户: {} 拒绝了通信请求!\n".format(other_name))
                    Connection_program.ready_text.insert("end", "目标用户: {} ,拒绝了通信请求!".format(other_name))
                    Connection_program.show_client_key_connect_flag = False
            else:
                # print("目标用户:{}，不处于等待状态".format(other_name))
                Connection_program.show_client_key_text.insert("end", "目标用户:{}, 不处于等待状态！\n".format(other_name))
                Connection_program.ready_text.insert("end", "目标用户:{}, 不处于等待状态！".format(other_name))
                Connection_program.show_client_key_connect_flag = False
        else:
            # print("\033[91m服务端拒绝了请求\033[0m")
            Connection_program.show_client_key_text.insert("end", "服务端拒绝了请求！\n")
            Connection_program.ready_text.insert("end", "服务端拒绝了请求！")
            Connection_program.show_client_key_connect_flag = False
        Connection_program.ready_text.config(state="disabled")

    # 定义发送消息的方法
    @staticmethod
    def show_client_key_send_function():
        if Connection_program.show_client_key_connect_flag is True:
            talk_data = Connection_program.show_client_key_entry.get()  # 获取发送的消息
            Connection_program.show_client_key_entry.delete(0, "end")  # 清空输入窗
            Connection_program.ready_text.config(state="normal")
            Connection_program.ready_text.delete("1.0", "end")
            if talk_data != "":
                data_socket = Connection_program.login_socket
                if talk_data == "exit" or talk_data == "退出" or talk_data == "@sever_wait_mode_active_this_connect_end":  # 判断是否主动中断通信
                    data_socket.send("@sever_wait_mode_active_this_connect_end".encode())
                    Connection_program.show_client_key_connect_flag = False
                    Connection_program.show_client_key_exit_button.config(state="normal")  # 退出按钮生效
                    Connection_program.ready_text.config(state="normal")
                    Connection_program.ready_text.delete("1.0", "end")
                    Connection_program.ready_text.insert("end", "您已结束会话，本次通信结束！")
                    Connection_program.ready_text.config(state="disabled")
                    Connection_program.show_client_key_input_button.config(state="disabled")  # 消息发送按钮失效
                    Connection_program.show_client_key_mode_text.config(state="normal")
                    Connection_program.show_client_key_mode_text.delete("1.0", "end")
                    Connection_program.show_client_key_mode_text.insert("1.0", "已结束通信")
                    Connection_program.show_client_key_mode_text.config(state="disabled")
                else:
                    Connection_program.show_client_key_text.insert("end", "{}: {}\n".format(Main_program.name, talk_data))  # 将发送的消息展示在界面上
                    # 在此处加入双棘轮算法
                    talk_data = Crypto_program.kdf_dh_encry_function(talk_data)
                    data_socket.send(talk_data.encode())
                    time.sleep(0.1)
                    data_socket.send(str(Crypto_program.kdf_dh_self_time_public_key).encode())
            else:
                Connection_program.ready_text.insert("发送的消息不能为空！")
            Connection_program.ready_text.config(state="disabled")

    # 结束通信按钮的方法
    @staticmethod
    def show_client_key_connect_end_function():
        if Connection_program.show_client_key_connect_flag is True:
            Connection_program.login_socket.send("@sever_wait_mode_active_this_connect_end".encode())
            Connection_program.show_client_key_connect_flag = False
            Connection_program.show_client_key_connect_close_button.config(state="disabled")  # 通信结束按钮失效
            Connection_program.show_client_key_input_button.config(state="normal")  # 消息发送按钮生效

    # 定义用户连接指定用户成功后启用的接收消息的多线程方法
    @staticmethod
    def create_wait_passive_accept(data_socket, other_name):
        while True:
            talk_data = data_socket.recv(Connection_program.Max_data).decode()
            if talk_data == "@client_wait_mode_passive_this_connect_end":
                Connection_program.show_client_key_connect_flag = False
                data_socket.send("@sever_wait_mode_passive_this_connect_end".encode())
                Connection_program.show_client_key_text.insert("end", "对方结束了会话，本次通信已结束\n")
                Connection_program.ready_text.config(state="normal")
                Connection_program.ready_text.delete("1.0", "end")
                Connection_program.ready_text.insert("end", "对方已结束会话，本次通信结束！")
                Connection_program.ready_text.config(state="disabled")
                break
            elif talk_data == "@client_wait_mode_active_this_connect_end":
                break
            else:
                # 此处加入双棘轮算法
                # print("接收到加密数据:{}".format(talk_data))
                Connection_program.show_client_key_text.insert("end", "接收到加密数据:{}\n".format(talk_data))
                key_data = data_socket.recv(Connection_program.Max_data).decode()
                Crypto_program.kdf_dh_other_new_time_public_key = key_data
                talk_data = Crypto_program.kdf_dh_decry_function(talk_data)
                Connection_program.show_client_key_text.insert("end", "\n")
                # print(other_name, ":", talk_data)
                Connection_program.show_client_key_text.insert("end", "{} : {}\n".format(other_name, talk_data))
            if Connection_program.show_client_key_connect_flag is False:
                break
        Connection_program.show_client_key_input_button.config(state="disabled")  # 消息发送按钮失效
        Connection_program.show_client_key_mode_text.config(state="normal")
        Connection_program.show_client_key_mode_text.delete("1.0", "end")
        Connection_program.show_client_key_mode_text.insert("1.0", "已结束通信")
        Connection_program.show_client_key_mode_text.config(state="disabled")
        Connection_program.show_client_key_connect_close_button.config(state="disabled")  # 结束通信按钮失效
        Connection_program.show_client_key_connect_start_button.config(state="normal")
        Connection_program.show_client_key_exit_button.config(state="normal")  # 退出按钮生效
        # print("接收消息线程已结束")
        Connection_program.show_client_key_text.insert("end", "接收消息线程已结束\n")

    # 聊天室模式 初始界面窗口
    @staticmethod
    def private_chat_room_mode_window():
        if Connection_program.private_room_mode_flag is True:  # 判断聊天室模式状态，防止重复发送请求指令
            flag = "OK"
        else:
            # 向服务端发送进入聊天室模式的指令
            Connection_program.login_socket.send("@sever_private_room_mode_join".encode())
            # 接收来自服务端的回复
            flag = Connection_program.login_socket.recv(Connection_program.Max_data).decode()
        if flag == "OK":  # 判断服务端返回结果
            Connection_program.private_room_mode_flag = True  # 改变标志量
            # 设置初始界面参数
            Window_program.private_chat_mode_frame = tk.Frame(root_window, height=500, width=800, bd=3, padx=15, pady=10, )
            Window_program.private_chat_mode_frame.place(anchor="center", relx=0.5, rely=0.5)
            # 消息提示窗口
            Connection_program.ready_text = tk.Text(Window_program.private_chat_mode_frame, height=3, width=45, bd=3, font=("黑体", 15), fg="red", padx=10, pady=10)
            Connection_program.ready_text.grid(padx=10, pady=10)
            Connection_program.ready_text.insert("end", "欢迎来到聊天室模式，{}".format(Main_program.name))
            Connection_program.ready_text.config(state="disabled")
            # 加入聊天室按钮
            tk.Button(Window_program.private_chat_mode_frame, padx=10, pady=10, font=("黑体", 15), text="加入聊天室", fg="blue", command=Connection_program.private_chat_room_window_to_guest).grid(padx=10, pady=10)
            # 创建聊天室按钮
            tk.Button(Window_program.private_chat_mode_frame, padx=10, pady=10, font=("黑体", 15), text="创建聊天室", fg="blue", command=Connection_program.private_chat_room_window_to_host).grid(padx=10, pady=10)
            # 退出按钮
            tk.Button(Window_program.private_chat_mode_frame, padx=10, pady=10, font=("黑体", 15), text="退出", fg="red", command=Connection_program.private_chat_room_window_to_interface_window).grid(padx=10, pady=10)

    # 由聊天室模式返回用户窗口的方法
    @staticmethod
    def private_chat_room_window_to_interface_window():
        if Connection_program.private_room_mode_flag is True:  # 判断当前客户端聊天室状态
            Connection_program.login_socket.send("@sever_private_room_mode_exit".encode())
            Connection_program.private_room_mode_flag = False
            Window_program.private_chat_mode_frame.destroy()
            Connection_program.interface_window()

    # 聊天室模式 窗口转换的方法
    @staticmethod
    def private_chat_room_window_to_host():
        Window_program.private_chat_mode_frame.destroy()
        Connection_program.private_chat_room_host_window()

    @staticmethod
    def private_chat_room_window_to_guest():
        Window_program.private_chat_mode_frame.destroy()
        Connection_program.private_chat_room_guest_window()

    # 聊天室模式 房主窗口
    @staticmethod
    def private_chat_room_host_window():
        # 初始设置参数
        Connection_program.private_chat_host_send_state = 1
        Connection_program.private_chat_room_password = "NONE"
        Connection_program.private_chat_room_member_num = 1
        Connection_program.private_chat_room_ready_flag = False
        # 设置窗口参数
        Window_program.private_chat_host_frame = tk.Frame(root_window, height=400, width=600, bd=3, padx=15, pady=10, )
        Window_program.private_chat_host_frame.place(anchor="center", relx=0.5, rely=0.5)
        # 窗口提示标签
        tk.Label(Window_program.private_chat_host_frame, fg="blue", font=("黑体", 15), padx=10, pady=5, text="用户 {} 的聊天室房主界面".format(Main_program.name)).grid(row=0, column=0, columnspan=3, padx=10, pady=10)
        # 聊天数据框
        Connection_program.private_chat_text = tk.Text(Window_program.private_chat_host_frame, height=30, width=50, bd=3, padx=15, pady=10, font=("黑体", 10))
        Connection_program.private_chat_text.insert("end", "请输入房间最大容纳人数(2-10)\n")
        Connection_program.private_chat_text.grid(row=1, column=0, columnspan=2, padx=10, pady=10)
        # 成员列表
        Connection_program.private_chat_member_text = tk.Text(Window_program.private_chat_host_frame, height=20, width=10, bd=3, padx=15, pady=10, font=("黑体", 15), fg="red")
        Connection_program.private_chat_member_text.insert("end", "成员列表\n")
        Connection_program.private_chat_member_text.config(state="disabled")
        Connection_program.private_chat_member_text.grid(row=1, column=2, padx=10, pady=10)
        # 消息提示框
        Connection_program.ready_text = tk.Text(Window_program.private_chat_host_frame, height=2, width=50, bd=3, padx=15, pady=10, font=("黑体", 15), fg="red")
        Connection_program.ready_text.insert("end", "请先设置房间参数，再创建房间")
        Connection_program.ready_text.config(state="disabled")
        Connection_program.ready_text.grid(row=2, column=0, columnspan=3, padx=10, pady=10)
        # 消息输入框
        Connection_program.private_chat_entry = tk.Entry(Window_program.private_chat_host_frame, width=38, bd=3, font=("黑体", 15), )
        Connection_program.private_chat_entry.grid(row=3, column=0, columnspan=2, padx=10, pady=10)
        # 消息发送按钮
        Connection_program.private_chat_send_button = tk.Button(Window_program.private_chat_host_frame, padx=10, pady=10, font=("黑体", 15), text="发送", fg="green", command=Connection_program.private_chat_host_send_function)
        Connection_program.private_chat_send_button.grid(row=3, column=2, padx=10, pady=10)
        # 创建房间的按钮
        Connection_program.private_chat_connect_start_button = tk.Button(Window_program.private_chat_host_frame, padx=10, pady=10, font=("黑体", 15), text="创建房间", fg="green", command=Connection_program.client_create_private_room_function)
        # Connection_program.private_chat_connect_start_button.config(state="disabled")
        Connection_program.private_chat_connect_start_button.grid(row=4, column=0, padx=10, pady=10)
        # 撤销房间的按钮
        Connection_program.private_chat_connect_close_button = tk.Button(Window_program.private_chat_host_frame, padx=10, pady=10, font=("黑体", 15), text="撤销房间", fg="red", command=Connection_program.private_chat_host_connect_close_function)
        Connection_program.private_chat_connect_close_button.config(state="disabled")
        Connection_program.private_chat_connect_close_button.grid(row=4, column=1, padx=10, pady=10)
        # 退出按钮
        Connection_program.private_chat_exit_button = tk.Button(Window_program.private_chat_host_frame, padx=10, pady=10, font=("黑体", 15), text="退出", fg="red", command=Connection_program.private_chat_host_window_to_mode_window)
        Connection_program.private_chat_exit_button.grid(row=4, column=2, padx=10, pady=10)

    # 聊天室模式 房主窗口退出的方法
    @staticmethod
    def private_chat_host_window_to_mode_window():
        Window_program.private_chat_host_frame.destroy()
        Connection_program.private_chat_room_mode_window()

    # 聊天室模式 房主消息发送按钮对应的方法
    @staticmethod
    def private_chat_host_send_function():
        talk_data = Connection_program.private_chat_entry.get()
        Connection_program.private_chat_entry.delete(0, "end")  # 清空输入框数据
        Connection_program.ready_text.config(state="normal")
        Connection_program.ready_text.delete("1.0", "end")
        if Connection_program.private_chat_host_send_state == 1:  # 人数输入
            if talk_data.isdigit():  # 判断输入是否合法
                if 2 <= int(talk_data) <= 10:
                    Connection_program.private_chat_room_member_num = int(talk_data)
                    Connection_program.private_chat_text.insert("end", "您设置的房间最大容纳人数为:{}\n".format(talk_data))
                    Connection_program.private_chat_text.insert("end", "请输入房间口令(默认“NONE”为无口令)\n")
                    Connection_program.ready_text.insert("end", "请输入房间口令(默认“NONE”为无口令)")
                    Connection_program.private_chat_host_send_state = 2
                else:
                    Connection_program.ready_text.insert("end", "请输入 2 - 10 之间人数的数字！")
            else:
                Connection_program.ready_text.insert("end", "请输入数字！")
        elif Connection_program.private_chat_host_send_state == 2:
            if talk_data != "":
                Connection_program.private_chat_room_password = talk_data
                Connection_program.private_chat_text.insert("end", "您设置的房间口令为:{}\n".format(talk_data))
                Connection_program.private_chat_send_button.config(state="disabled")  # 发送按钮失效
                Connection_program.ready_text.insert("end", "房间参数设置完毕，可以创建房间！")
                Connection_program.private_chat_room_ready_flag = True
            else:
                Connection_program.ready_text.insert("end", "房间口令输入不能为空！")
        elif Connection_program.private_chat_host_send_state == 3:
            if talk_data != "@sever_private_room_exit":
                if talk_data != "":
                    Connection_program.login_socket.send((Main_program.name + ":" + talk_data).encode())
                else:
                    Connection_program.ready_text.insert("end", "输入不可为空！")
            else:
                Connection_program.ready_text.insert("end", "非法输入！")
        Connection_program.ready_text.config(state="disabled")

    # 聊天室模式 房主撤销房间的方法
    @staticmethod
    def private_chat_host_connect_close_function():
        if Connection_program.private_chat_host_send_state == 3:
            Connection_program.login_socket.send("@sever_private_room_exit".encode())  # 发送撤销房间的消息
            Connection_program.private_chat_connect_close_button.config(state="disabled")  # 撤销房间的按钮失效
            Connection_program.private_chat_send_button.config(state="disabled")  # 消息发送按钮失效
            Connection_program.private_chat_text.insert("end", "您撤销了房间！")
            Connection_program.private_chat_host_send_state = 0

    # 聊天室模式  更新房间的成员的方法
    @staticmethod
    def private_chat_update_member_text(mode, name):  # mode： 1 添加， 2 移除
        if mode == 1:
            Connection_program.private_chat_member_list.append(name)
            Connection_program.private_chat_room_member_num += 1
        else:
            if name in Connection_program.private_chat_member_list:
                Connection_program.private_chat_member_list.remove(name)
                Connection_program.private_chat_room_member_num -= 1
        Connection_program.private_chat_member_text.config(state="normal")
        Connection_program.private_chat_member_text.delete("1.0", "end")
        for item in Connection_program.private_chat_member_list:
            Connection_program.private_chat_member_text.insert("end", item)
            Connection_program.private_chat_member_text.insert("end", "\n")

    """
    # 弃稿
    # 定义客户端用户向服务端查询及创建聊天室房间的方法  聊天室模式界面
    @staticmethod
    def client_create_connect_room(data_socket):
        if Connection_program.private_room_mode_flag is True:  # 判断聊天室模式状态，防止重复发送请求指令
            flag = "OK"
        else:
            # 向服务端发送进入聊天室模式的指令
            data_socket.send("@sever_private_room_mode_join".encode())
            # 接收来自服务端的回复
            flag = data_socket.recv(Connection_program.Max_data).decode()
        if flag == "OK":
            Connection_program.private_room_mode_flag = True  # 改变聊天室模式状态
            print("欢迎来到聊天室模式:{}".format(Main_program.name))
            while True:
                print("1 查询以及加入聊天室")
                print("2 创建聊天室房间")
                print("3 退出聊天室模式")
                change_flag = input("请选择操作:")
                if change_flag in ["1", "2", "3"]:
                    break
                else:
                    print("\033[91m请选择正确的操作序号！\033[0m")
            if change_flag == "1":
                # 调用查询当前聊天室的方法
                Connection_program.client_query_private_join_room_function()
            elif change_flag == "2":
                # 调用创建聊天室的方法
                Connection_program.client_create_private_room_function()
            else:
                print("正在退出聊天室模式")
                # 向服务端发送退出聊天室模式的方法
                data_socket.send("@sever_private_room_mode_exit".encode())
                Connection_program.private_room_mode_flag = False
        else:
            print("\033[91m进入聊天室模式失败！\033[0m")
        Connection_program.private_room_mode_flag = False
        # 调用返回用户界面的方法
        Connection_program.interface_main(data_socket)
     
    """

    # 定义创建个人聊天室的方法  房主方法
    @staticmethod
    def client_create_private_room_function():
        # 改变相关组件参数
        Connection_program.ready_text.config(state="normal")
        Connection_program.ready_text.delete("1.0", "end")
        if Connection_program.private_chat_room_ready_flag is True:
            Connection_program.private_chat_connect_start_button.config(state="disabled")  # 创建房间的按钮失效
            Connection_program.private_chat_exit_button.config(state="disabled")  # 退出按钮失效
            Connection_program.private_chat_text.config(state="normal")
            # 向服务端发起创建请求
            data_socket = Connection_program.login_socket
            data_socket.send("@sever_private_room_create".encode())  # 向服务端发送请求创建个人聊天室的方法
            Connection_program.private_chat_text.insert("end", "已向服务端发送创建房间的请求！\n")
            flag = data_socket.recv(Connection_program.Max_data).decode()  # 接受服务端的回复
            if flag == "OK":  # 判断客户端回复结果
                Connection_program.private_chat_text.insert("end", "请求成功！正在发送房间参数\n")
                Connection_program.login_socket.send(str(Connection_program.private_chat_room_member_num).encode())  # 发送房间的最大容纳人数
                time.sleep(0.1)  # 时延防止粘包
                Connection_program.login_socket.send(str(Connection_program.private_chat_room_password).encode())  # 发送房间的口令
                # 接收返回消息
                flag = data_socket.recv(Connection_program.Max_data).decode()
                if flag == "OK":
                    Connection_program.private_room_talk_flag = True  # 改变聊天室工作状态
                    # 创建接收消息多线程
                    recv_data_th = threading.Thread(target=Connection_program.private_room_recv_data_function, args=(data_socket,))
                    recv_data_th.start()  # 启用多线程
                    # print("房间创建成功")
                    Connection_program.ready_text.delete("1.0", "end")
                    Connection_program.ready_text.insert("end", "房间创建成功！")
                    Connection_program.private_chat_text.insert("end", "您的房间已创建！\n")
                    Connection_program.private_chat_host_send_state = 3  # 改变消息发送按钮状态
                    Connection_program.private_chat_send_button.config(state="normal")  # 消息发送按钮生效
                    Connection_program.private_chat_connect_close_button.config(state="normal")  # 撤销房间的按钮生效
                else:
                    # print("\033[91m房间创建失败\033[0m")
                    Connection_program.ready_text.delete("1.0", "end")
                    Connection_program.ready_text.insert("end", "房间创建失败！")
                    Connection_program.private_chat_text.insert("end", "房间创建失败！")
                    Connection_program.private_chat_exit_button.config(state="normal")  # 退出按钮生效
                    Connection_program.private_chat_connect_start_button.config(state="normal")  # 创建房间的按钮生效
                    Connection_program.private_chat_host_send_state = 1
                    Connection_program.private_chat_room_ready_flag = False
            else:
                # print("\033[91m请求失败\033[0m")
                Connection_program.ready_text.insert("end", "请求创建房间失败！")
                Connection_program.private_chat_text.config(state="disabled")
                Connection_program.private_chat_exit_button.config(state="normal")  # 退出按钮生效
        else:
            Connection_program.ready_text.insert("end", "请先设置房间参数！")
        Connection_program.ready_text.config(state="disabled")

    # 聊天室模式 成员窗口
    @staticmethod
    def private_chat_room_guest_window():
        # 初始设置参数
        Connection_program.private_chat_guest_send_state = 0
        Connection_program.private_chat_room_ready_flag = False
        # 设置窗口参数
        Window_program.private_chat_guest_frame = tk.Frame(root_window, height=400, width=600, bd=3, padx=15, pady=10, )
        Window_program.private_chat_guest_frame.place(anchor="center", relx=0.5, rely=0.5)
        # 窗口提示标签
        tk.Label(Window_program.private_chat_guest_frame, fg="blue", font=("黑体", 15), padx=10, pady=5, text="用户 {} 的聊天室成员界面".format(Main_program.name)).grid(row=0, column=0, columnspan=3, padx=10, pady=10)
        # 聊天数据框
        Connection_program.private_chat_text = tk.Text(Window_program.private_chat_guest_frame, height=30, width=70, bd=3, padx=15, pady=10, font=("黑体", 10), )
        Connection_program.private_chat_text.insert("end", "请先查询房间状况\n")
        Connection_program.private_chat_text.config(state="disabled")
        Connection_program.private_chat_text.grid(row=1, column=0, columnspan=3, padx=10, pady=10)
        # 消息提示框
        Connection_program.ready_text = tk.Text(Window_program.private_chat_guest_frame, height=2, width=50, bd=3, padx=15, pady=10, font=("黑体", 15), fg="red", )
        Connection_program.ready_text.insert("end", "等待加入房间")
        Connection_program.ready_text.config(state="disabled")
        Connection_program.ready_text.grid(row=2, column=0, columnspan=3, padx=10, pady=10)
        # 消息输入框
        Connection_program.private_chat_entry = tk.Entry(Window_program.private_chat_guest_frame, width=38, bd=3, font=("黑体", 15), )
        Connection_program.private_chat_entry.grid(row=3, column=0, columnspan=2, padx=10, pady=10)
        # 消息发送按钮
        Connection_program.private_chat_send_button = tk.Button(Window_program.private_chat_guest_frame, padx=10, pady=10, font=("黑体", 15), text="发送", fg="green", command=Connection_program.private_chat_room_guest_send_function)
        Connection_program.private_chat_send_button.config(state="disabled")
        Connection_program.private_chat_send_button.grid(row=3, column=2, padx=10, pady=10)
        # 开启通信按钮
        Connection_program.private_chat_connect_start_button = tk.Button(Window_program.private_chat_guest_frame, padx=10, pady=10, font=("黑体", 15), text="查询房间", fg="green", command=Connection_program.client_query_private_join_room_function)
        Connection_program.private_chat_connect_start_button.grid(row=4, column=0, padx=10, pady=10)
        # 结束通信按钮
        Connection_program.private_chat_connect_close_button = tk.Button(Window_program.private_chat_guest_frame, padx=10, pady=10, font=("黑体", 15), text="退出房间", fg="red", command=Connection_program.private_chat_room_guest_connect_close_function)
        Connection_program.private_chat_connect_close_button.config(state="disabled")
        Connection_program.private_chat_connect_close_button.grid(row=4, column=1, padx=10, pady=10)
        # 退出按钮
        Connection_program.private_chat_exit_button = tk.Button(Window_program.private_chat_guest_frame, padx=10, pady=10, font=("黑体", 15), text="退出", fg="red", command=Connection_program.private_chat_guest_window_to_mode_widow)
        Connection_program.private_chat_exit_button.grid(row=4, column=2, padx=10, pady=10)

    # 聊天室模式  成员窗口退出的方法
    @staticmethod
    def private_chat_guest_window_to_mode_widow():
        Window_program.private_chat_guest_frame.destroy()
        Connection_program.private_chat_room_mode_window()

    # 用户查询聊天室及加入的方法  房间的成员方法
    @staticmethod
    def client_query_private_join_room_function():
        # 改变组件参数
        Connection_program.private_chat_connect_start_button.config(state="disabled")  # 查询房间的按钮失效
        Connection_program.private_chat_exit_button.config(state="disabled")  # 退出按钮失效
        Connection_program.private_chat_text.config(state="normal")
        # 发送请求查询当前房间的状况
        data_socket = Connection_program.login_socket
        next_flag = False
        target_room_name = ""
        target_room_encry_state = ""
        # print("正在请求中...")
        Connection_program.private_chat_text.insert("end", "正在请求中...\n")
        Connection_program.private_room_host_name_list = []  # 房主名列表
        Connection_program.private_room_now_person_num_list = []  # 房间现人数列表
        Connection_program.private_room_max_person_num_list = []  # 房间最大容纳人数列表
        Connection_program.private_room_encry_list = []  # 房间加密状态列表
        # 向服务端发送聊天室查询请求
        data_socket.send("@sever_private_room_query".encode())
        flag = data_socket.recv(Connection_program.Max_data).decode()
        if flag == "OK":  # 判断返回结果
            # print("正在获得及处理数据中...")
            Connection_program.private_chat_text.insert("end", "正在获得及处理数据中...\n")
            while True:
                name_data = data_socket.recv(Connection_program.Max_data).decode()  # 接收房主名
                if name_data != "@all_data_end":  # 判断数据接收结束标志
                    Connection_program.private_room_host_name_list.append(name_data)
                    now_person_num = data_socket.recv(Connection_program.Max_data).decode()  # 接收现人数
                    Connection_program.private_room_now_person_num_list.append(now_person_num)
                    max_person_num = data_socket.recv(Connection_program.Max_data).decode()  # 接收最大人数
                    Connection_program.private_room_max_person_num_list.append(max_person_num)
                    encry_state = data_socket.recv(Connection_program.Max_data).decode()  # 接收加密状态
                    Connection_program.private_room_encry_list.append(encry_state)
                else:
                    break
            if len(Connection_program.private_room_host_name_list) != 0:
                # print("当前存在的聊天室房间如下")
                Connection_program.private_chat_text.insert("end", "当前存在的聊天室房间如下:\n")
                room_num = int(len(Connection_program.private_room_host_name_list))
                for i in range(0, room_num):
                    # print("{} 房主名:{},人数:{}/{},加密状态:{}".format(i, private_room_name_list[i], private_room_now_person_num_list[i], private_room_max_person_num_list[i], private_room_encry_list[i]))
                    Connection_program.private_chat_text.insert("end", "{} 房主名:{},人数:{}/{},加密状态:{}\n".format(i, Connection_program.private_room_host_name_list[i], Connection_program.private_room_now_person_num_list[i], Connection_program.private_room_max_person_num_list[i], Connection_program.private_room_encry_list[i]))
                Connection_program.private_chat_guest_send_state = 1
                Connection_program.private_chat_room_ready_flag = True
                Connection_program.private_chat_send_button.config(state="normal")  # 消息发送按钮生效
                Connection_program.ready_text.config(state="normal")
                Connection_program.ready_text.delete("1.0", "end")
                Connection_program.ready_text.insert("end", "请输入对应房间序号以加入对应房间，或输入“退出”不加入房间")
                Connection_program.ready_text.config(state="disabled")
            else:
                # print("当前暂无聊天室")
                Connection_program.private_chat_text.insert("end", "当前暂无聊天室！\n")
                data_socket.send("@sever_private_room_not_join".encode())
                Connection_program.private_chat_exit_button.config(state="normal")  # 退出按钮生效
        else:
            # print("\033[91m查询失败！\033[0m")
            Connection_program.private_chat_text.insert("end", "查询失败！\n")

    # 聊天室模式 成员发送消息按钮对应的方法
    @staticmethod
    def private_chat_room_guest_send_function():
        talk_data = Connection_program.private_chat_entry.get()
        Connection_program.private_chat_entry.delete(0, "end")
        Connection_program.ready_text.config(state="normal")
        Connection_program.ready_text.delete("1.0", "end")
        if Connection_program.private_chat_room_ready_flag is True:  # 判断是否查询了房间的状况
            if Connection_program.private_chat_guest_send_state == 1:  # 判断此时的状态
                room_num = len(Connection_program.private_room_host_name_list)  # 获得房间的数量
                if talk_data.isdigit():
                    talk_data = int(talk_data)
                    if talk_data in range(0, room_num):
                        if int(Connection_program.private_room_max_person_num_list[talk_data]) - int(Connection_program.private_room_now_person_num_list[talk_data]) > 0:  # 判断目标房间是否还有多余的空间
                            target_room_name = Connection_program.private_room_host_name_list[talk_data]
                            Connection_program.login_socket.send("@sever_private_room_join_target".encode())  # 向服务端发送加入房间的请求
                            time.sleep(0.1)  # 时延防止粘包
                            Connection_program.login_socket.send(target_room_name.encode())  # 发送房主名
                            if Connection_program.private_room_encry_list[talk_data] == "NO":  # 判断目标房间是否处于加密状态
                                Connection_program.login_socket.send("NONE".encode())
                                flag = Connection_program.login_socket.recv(Connection_program.Max_data).decode()
                                if flag == "OK":  # 判断是否加入了目标用户房间
                                    Connection_program.ready_text.insert("end", "加入目标用户房间成功！")
                                    Connection_program.private_chat_guest_send_state = 3  # 改变按键状态
                                    Connection_program.private_chat_connect_close_button.config(state="normal")  # 结束通信按钮生效
                                    # 启用接收消息的多线程
                                    recv_th = threading.Thread(target=Connection_program.private_room_recv_data_function, args=(Connection_program.login_socket, ))
                                    recv_th.start()
                                else:
                                    Connection_program.ready_text.insert("end", "加入目标用户房间失败！")
                                    Connection_program.private_chat_guest_send_state = 1  # 改变发送按钮状态
                                    Connection_program.private_chat_exit_button.config(state="normal")  # 退出按钮生效
                                    Connection_program.private_chat_exit_button.config(state="disabled")  # 消息发送按钮失效
                            else:
                                Connection_program.ready_text.insert("end", "请输入该房间的口令")
                                Connection_program.private_chat_guest_send_state = 2
                        else:
                            # print("您选择的房间已满，请重新选择，或输入“退出”")
                            Connection_program.ready_text.insert("end", "您选择的房间已满，请重新选择，或输入“退出”")
                    else:
                        Connection_program.ready_text.insert("end", "请输入已有的房间序号！")
                elif talk_data == "退出":
                    Connection_program.ready_text.insert("end", "您选择了不加入聊天室！")
                    Connection_program.login_socket.send("@sever_private_room_not_join".encode())  # 向服务端发送中断加入聊天室的通知
                    Connection_program.private_chat_send_button.config(state="disabled")  # 消息发送按钮失效
                    Connection_program.private_chat_exit_button.config(state="normal")  # 退出按钮生效
                else:
                    # print("\033[91m请输入正确的房间序号\033[0m")
                    Connection_program.ready_text.insert("end", "请输入正确的房间序号！")
            elif Connection_program.private_chat_guest_send_state == 2:  # 房间的口令输入
                Connection_program.login_socket.send(talk_data.encode())  # 发送用户输入的口令
                flag = Connection_program.login_socket.recv(Connection_program.Max_data).decode()
                if flag == "OK":  # 判断房间加入结果
                    Connection_program.ready_text.insert("end", "加入房间成功！")
                    Connection_program.private_chat_guest_send_state = 3
                    Connection_program.private_chat_connect_close_button.config(state="normal")  # 退出房间的按钮生效
                    # 启用接收消息的多线程
                    recv_th = threading.Thread(target=Connection_program.private_room_recv_data_function, args=(Connection_program.login_socket,))
                    recv_th.start()
                else:
                    Connection_program.ready_text.insert("end", "加入房间失败！")
                    Connection_program.private_chat_guest_send_state = 0
                    Connection_program.private_chat_send_button.config(state="disabled")  # 消息发送按钮失效
                    Connection_program.private_chat_exit_button.config(state="normal")  # 退出按钮生效
            elif Connection_program.private_chat_guest_send_state == 3:  # 正常通信
                if talk_data != "" and talk_data != "输入的消息不能为空！":
                    talk_data = Main_program.name + ":" + talk_data
                    Connection_program.login_socket.send(talk_data.encode())
                else:
                    Connection_program.ready_text.insert("end", "输入的消息不能为空！")
        else:
            Connection_program.ready_text.insert("end", "请先查询房间状态！")
        Connection_program.ready_text.config(state="disabled")

    # 聊天室模式 成员退出房间的方法
    @staticmethod
    def private_chat_room_guest_connect_close_function():
        if Connection_program.private_chat_guest_send_state == 3:  # 判断发送按钮此时的状态
            Connection_program.login_socket.send("@sever_private_room_active_exit".encode())  # 向服务端发送退出房间提示
            Connection_program.private_chat_send_button.config(state="disabled")  # 消息发送按钮失效
            Connection_program.private_chat_connect_close_button.config(state="disabled")  # 退出房间的按钮失效
            Connection_program.private_chat_exit_button.config(state="normal")  # 退出按钮生效
            Connection_program.private_chat_guest_send_state = 1


    # 定义客户端 聊天室模式 接收消息的多线程
    @staticmethod
    def private_room_recv_data_function(data_socket):
        Connection_program.private_chat_text.insert("end", "您已进入房间\n")
        while True:
            talk_data = data_socket.recv(Connection_program.Max_data).decode()
            if talk_data != "@client_private_room_exit":
                if talk_data != "@client_private_room_destroy":
                    if "@client_private_chat_mode_append_member:" in talk_data:
                        Connection_program.private_chat_update_member_text(1, talk_data[40:])
                    elif "@client_private_chat_mode_remove_member:" in talk_data:
                        Connection_program.private_chat_update_member_text(2, talk_data[40:])
                    else:
                        # print(talk_data)
                        talk_data = talk_data + "\n"
                        Connection_program.private_chat_text.insert("end", talk_data)
                else:
                    # print("房主关闭了房间")
                    Connection_program.ready_text.config(state="normal")
                    Connection_program.ready_text.delete("1.0", "end")
                    Connection_program.ready_text.insert("end", "房主撤销了房间！")
                    Connection_program.ready_text.config(state="disabled")
                    if len(Connection_program.private_room_host_name_list) != 0:  # 通过判断该列表是否为0，来判断该接收线程的所属是房主还是成员
                        Connection_program.login_socket.send("@sever_private_room_passive_exit".encode())  # 返回服务端对应的用户线程
                    break
            else:
                Connection_program.ready_text.config(state="normal")
                Connection_program.ready_text.delete("1.0", "end")
                Connection_program.ready_text.insert("end", "您已退出了房间！")
                Connection_program.ready_text.config(state="disabled")
                break
        Connection_program.private_chat_send_button.config(state="disabled")  # 消息发送按钮失效
        Connection_program.private_chat_connect_close_button.config(state="disabled")  # 结束通信按钮失效
        Connection_program.private_chat_exit_button.config(state="normal")  # 退出按钮生效
        Connection_program.private_room_talk_flag = False
        Connection_program.private_chat_guest_send_state = 1
        Connection_program.private_chat_host_send_state = 1
        Connection_program.private_chat_room_ready_flag = False
        # print("已退出聊天室")
        Connection_program.private_chat_text.insert("end", "已退出聊天室！\n")

    # 等待模式数据显示窗口
    @staticmethod
    def wait_mode_window():
        # 设置初始变量
        Connection_program.wait_mode_alive_flag = False
        Connection_program.wait_mode_connect_flag = False
        Connection_program.wait_mode_connect_state = 0  # 初始设置为未连接到用户状态
        # 设置窗口参数
        Window_program.wait_mode_frame = tk.Frame(root_window, height=500, width=950, bd=3, padx=15, pady=10)
        Window_program.wait_mode_frame.place(anchor="center", relx=0.5, rely=0.5)
        # 窗口提示标签
        tk.Label(Window_program.wait_mode_frame, fg="blue", font=("黑体", 15), padx=10, pady=5, text="用户 {} 的等待模式界面".format(Main_program.name)).grid(row=0, column=0, columnspan=4, padx=10, pady=10)
        # 数据展示文本框
        Connection_program.wait_mode_text = tk.Text(Window_program.wait_mode_frame, height=30, width=95, bd=3, font=("黑体", 10), fg="black", padx=10, pady=10)
        Connection_program.wait_mode_text.config(state="disabled")
        Connection_program.wait_mode_text.grid(row=1, column=0, columnspan=4, padx=10, pady=10)
        # 消息提示框
        Connection_program.ready_text = tk.Text(Window_program.wait_mode_frame, height=3, width=40, bd=3, font=("黑体", 15), fg="red", padx=10, pady=10)
        Connection_program.ready_text.config(state="disabled")
        Connection_program.ready_text.grid(row=2, column=0, columnspan=3, padx=10, pady=10)
        # 通信状态显示框
        Connection_program.wait_mode_state_text = tk.Text(Window_program.wait_mode_frame, height=3, width=20, bd=3, font=("黑体", 15), fg="red", padx=10, pady=10)
        Connection_program.wait_mode_state_text.insert("end", "等待进入等待模式")
        Connection_program.wait_mode_state_text.config(state="disabled")
        Connection_program.wait_mode_state_text.grid(row=2, column=3, padx=10, pady=10)
        # 数据输入
        Connection_program.wait_mode_entry = tk.Entry(Window_program.wait_mode_frame, width=42, bd=3, font=("黑体", 15), fg="black", )
        Connection_program.wait_mode_entry.grid(row=3, column=0, columnspan=3, padx=10, pady=10)
        # 数据发送按钮
        Connection_program.wait_mode_send_button = tk.Button(Window_program.wait_mode_frame, padx=10, pady=10, font=("黑体", 15), text="发送", fg="green", command=Connection_program.wait_mode_send_data_function)
        Connection_program.wait_mode_send_button.config(state="disabled")
        Connection_program.wait_mode_send_button.grid(row=3, column=3, padx=10, pady=10)
        # 进入等待按钮
        Connection_program.wait_mode_connect_start_button = tk.Button(Window_program.wait_mode_frame, padx=10, pady=10, font=("黑体", 15), text="进入等待", fg="green", command=Connection_program.client_join_wait_mode)
        Connection_program.wait_mode_connect_start_button.grid(row=4, column=0, padx=10, pady=10)
        # 结束本次通信按钮
        Connection_program.wait_mode_connect_next_button = tk.Button(Window_program.wait_mode_frame, padx=10, pady=10, font=("黑体", 15), text="结束通信", fg="red", command=Connection_program.wait_mode_connect_next_function)
        Connection_program.wait_mode_connect_next_button.config(state="disabled")
        Connection_program.wait_mode_connect_next_button.grid(row=4, column=1, padx=10, pady=10)
        # 结束等待模式按钮
        Connection_program.wait_mode_connect_close_button = tk.Button(Window_program.wait_mode_frame, padx=10, pady=10, font=("黑体", 15), text="退出等待", fg="red", command=Connection_program.wait_mode_exit_function)
        Connection_program.wait_mode_connect_close_button.config(state="disabled")
        Connection_program.wait_mode_connect_close_button.grid(row=4, column=2, padx=10, pady=10)
        # 退出按钮
        Connection_program.wait_mode_exit_button = tk.Button(Window_program.wait_mode_frame, padx=10, pady=10, font=("黑体", 15), text="退出", fg="red", command=Connection_program.wait_mode_window_to_interface_window)
        Connection_program.wait_mode_exit_button.grid(row=4, column=3, padx=10, pady=10)

    # 由等待模式窗口 转向 用户窗口的方法
    @staticmethod
    def wait_mode_window_to_interface_window():
        if Connection_program.wait_mode_alive_flag is False:  # 判断当前等待模式是否处于激活状态
            Window_program.wait_mode_frame.destroy()
            Connection_program.interface_window()
        else:
            Connection_program.ready_text.config(state="normal")
            Connection_program.ready_text.delete("1.0", "end")
            Connection_program.ready_text.insert("end", "您当前处于通信状态，无法直接退出！")
            Connection_program.ready_text.config(state="disabled")

    # 定义客户端用户进入等待模式的方法  (等待模式 主动态)
    @staticmethod
    def client_join_wait_mode():
        # 改变相关组件参数设置
        Connection_program.wait_mode_exit_button.config(state="disabled")  # 截止本次通信连接完成，退出按钮失效
        Connection_program.wait_mode_connect_start_button.config(state="disabled")  # 截止本次通信结束，进入等待按钮失效
        Connection_program.wait_mode_text.config(state="normal")
        Connection_program.ready_text.config(state="normal")
        Connection_program.ready_text.delete("1.0", "end")
        # 通信连接
        data_socket = Connection_program.login_socket
        # print("正在请求中...")
        Connection_program.wait_mode_text.insert("end", "正在请求中...\n")
        data_socket.send("@sever_wait_mode_join".encode())
        flag = data_socket.recv(Connection_program.Max_data).decode()  # 接收服务端回复结果
        if flag == "OK":  # 判断回复结果
            # print("已成功进入等待模式")
            Connection_program.ready_text.insert("end", "进入等待模式成功！")
            Connection_program.wait_mode_text.insert("end", "进入等待模式成功！\n")
            Connection_program.client_wait_mode_flag = True
            # 创建等待线程并开启
            th = threading.Thread(target=Connection_program.create_wait_active_accept, args=(data_socket, ))
            th.start()
            # 改变相关组件的参数
            Connection_program.wait_mode_connect_close_button.config(state="normal")  # 退出等待按钮生效
            Connection_program.wait_mode_state_text.config(state="normal")
            Connection_program.wait_mode_state_text.delete("1.0", "end")
            Connection_program.wait_mode_state_text.insert("end", "当前正处于等待模式")
            Connection_program.wait_mode_state_text.config(state="disabled")
        else:
            # print("\033[91m进入等待模式失败！\033[0m")
            Connection_program.ready_text.insert("end", "进入等待模式失败！")
            Connection_program.wait_mode_connect_start_button.config(state="normal")  # 进入等待按钮生效
            Connection_program.wait_mode_exit_button.config(state="normal")  # 退出等待模式按钮生效
        Connection_program.ready_text.config(state="disabled")
        Connection_program.wait_mode_text.config(state="disabled")

    # 等待模式 主动态 消息发送按钮的方法
    @staticmethod
    def wait_mode_send_data_function():
        if Connection_program.client_wait_mode_flag is True:  # 判断当前等待模式状态
            if Connection_program.client_wait_mode_connect_flag is True:  # 判断当前通信是否连接到了其他用户
                data_socket = Connection_program.login_socket
                talk_data = Connection_program.wait_mode_entry.get()  # 获取用户输入的数据
                Connection_program.wait_mode_entry.delete(0, "end")  # 清空输入数据
                if Connection_program.wait_mode_connect_state == 1:  # 判断是否连接到了其他用户
                    if str(talk_data) == "1":  # 判断是否进行 X3DH 协议下的通信验证连接
                        # 通知对方用户请求结果
                        data_socket.send("OK".encode())
                        # 开始进行 X3DH 协议下的验证连接
                        # print("正在进行 X3DH 协议下的验证...")
                        Connection_program.wait_mode_text.insert("end", "正在进行 X3DH 协议下的验证...\n")
                    else:
                        data_socket.send("NO".encode())
                        Connection_program.wait_mode_text.insert("end", "您拒绝了与用户: {} 的通信连接！\n".format(Connection_program.client_wait_mode_other_name))
                    Connection_program.wait_mode_send_button.config(state="disabled")  # 改变发送按钮状态
                elif Connection_program.wait_mode_connect_state == 2:
                    # 进行正常的通信会话
                    # 此处加入双棘轮算法
                    Connection_program.wait_mode_text.insert("end", "{}: {}\n".format(Main_program.name, talk_data))  # 将发送的消息显示到屏幕上
                    talk_data = Crypto_program.kdf_dh_encry_function(talk_data)
                    data_socket.send(talk_data.encode())
                    time.sleep(0.1)
                    data_socket.send(str(Crypto_program.kdf_dh_self_time_public_key).encode())
                else:
                    Connection_program.ready_text.config(state="normal")
                    Connection_program.ready_text.delete("1.0", "end")
                    Connection_program.ready_text.insert("end", "数据判断异常！")
                    Connection_program.ready_text.config(state="disabled")

    # 等待模式 主动态 退出等待的按钮的方法
    @staticmethod
    def wait_mode_exit_function():
        if Connection_program.client_wait_mode_flag is True:  # 判断等待模式激活状态
            if Connection_program.client_wait_mode_connect_flag is False:
                Connection_program.client_wait_mode_flag = False  # 更改状态
                Connection_program.login_socket.send("@sever_wait_mode_exit".encode())  # 向服务端发送退出等待模式的方法
                Connection_program.wait_mode_connect_close_button.config(state="disabled")  # 退出等待按钮失效
                Connection_program.wait_mode_connect_start_button.config(state="normal")  # 进入等待按钮生效
                Connection_program.wait_mode_exit_button.config(state="disabled")  # 退出等待模式按钮失效
            else:
                Connection_program.ready_text.config(state="normal")
                Connection_program.ready_text.delete("1.0", "end")
                Connection_program.ready_text.insert("end", "您当前正处于通信状态，请先退出通信状态！")
                Connection_program.ready_text.config(state="disabled")

    # 等待模式 主动态 结束通信按钮的方法
    @staticmethod
    def wait_mode_connect_next_function():
        if Connection_program.client_wait_mode_flag is True:  # 判断等待模式激活状态
            if Connection_program.client_wait_mode_connect_flag is True:  # 判断通信连接状态
                Connection_program.client_wait_mode_connect_flag = False  # 更改通信状态
                Connection_program.login_socket.send("@sever_wait_mode_active_this_connect_end".encode())
                Connection_program.wait_mode_connect_next_button.config(state="disabled")  # 结束通信按钮失效
                Connection_program.wait_mode_send_button.config(state="disabled")  # 消息发送按钮失效
                Connection_program.wait_mode_connect_close_button.config(state="normal")  # 退出等待模式按钮生效
                Connection_program.ready_text.config(state="normal")
                Connection_program.ready_text.delete("1.0", "end")
                Connection_program.ready_text.insert("end", "你已主动结束了与用户:{} 的通信!".format(Connection_program.client_wait_mode_other_name))
                Connection_program.ready_text.config(state="disabled")

    # 定义 等待模式 主动态 用户的接收线程
    @staticmethod
    def create_wait_active_accept(data_socket):
        # 预处理相关组件参数设置
        Connection_program.wait_mode_text.config(state="normal")  # 改变数据展示框状态
        # print("等待模式接收线程已启用")
        Connection_program.wait_mode_text.insert("end", "等待模式接收线程已启用！\n")
        while True:
            talk_data = data_socket.recv(Connection_program.Max_data).decode()
            Connection_program.client_wait_mode_connect_flag = True
            if talk_data != "@client_wait_mode_exit":  # 判断是否结束线程
                other_name = talk_data  # 接收对方用户名
                Connection_program.ready_text.config(state="normal")
                Connection_program.ready_text.delete("1.0", "end")
                # print("用户 {} 请求与您建立通信，若同意请输入“1”:".format(other_name))
                Connection_program.ready_text.insert("end", "用户: {},请求与您建立通信，若同意请输入“1".format(other_name))
                Connection_program.ready_text.config(state="disabled")
                Connection_program.wait_mode_send_button.config(state="normal")  # 消息发送按钮生效
                Connection_program.wait_mode_connect_state = 1  # 改变通信状态
                Connection_program.client_wait_mode_other_name = other_name
                talk_data = data_socket.recv(Connection_program.Max_data).decode()  # 接收服务端的判断结果
                if talk_data == "OK":  # 判断是否进行 X3DH 验证
                    # 改变相关组件的参数设置
                    Connection_program.wait_mode_send_button.config(state="disabled")  # 截止 X3DH 协商密钥计算完成，消息发送按钮失效
                    Connection_program.ready_text.config(state="normal")
                    Connection_program.ready_text.delete("1.0", "end")
                    Connection_program.ready_text.insert("end", "您同意了与用户:{} 的通信连接请求！".format(other_name))
                    Connection_program.ready_text.config(state="disabled")
                    # 开始进行 X3DH 协议下的通信连接
                    # 接收使用的我方一次性公钥
                    self_time_public_key = data_socket.recv(Connection_program.Max_data).decode()
                    # print("接收到对方使用的我方的一次性公钥: {}".format(self_time_public_key))
                    Connection_program.wait_mode_text.insert("end", "接收到对方使用的我方的一次性公钥:{}\n".format(self_time_public_key))
                    # 接收对方身份公钥
                    other_public_key = data_socket.recv(Connection_program.Max_data).decode()
                    # print("接收到对方的身份公钥为: {}".format(other_public_key))
                    Connection_program.wait_mode_text.insert("end", "接收到对方的身份公钥为:{}\n".format(other_public_key))
                    # 接收对方临时公钥
                    other_time_public_key = data_socket.recv(Connection_program.Max_data).decode()
                    # print("接收到对方使用的临时公钥: {}".format(other_time_public_key))
                    Connection_program.wait_mode_text.insert("end", "接收到对方使用的临时公钥:{}\n".format(other_time_public_key))
                    # 调用 X3DH 密钥生成的算法
                    flag, Connection_program.client_wait_mode_x3dh_key = Crypto_program.x3dh_passive_create(self_time_public_key, other_name, other_public_key, other_time_public_key)
                    if flag is True:  # 判断计算结果
                        # print("计算成功！")
                        Connection_program.wait_mode_text.insert("end", "计算成功！\n")
                        # 向对方发送计算完成通知
                        data_socket.send("OK".encode())
                        # print("计算获得的密钥为：{}".format(Connection_program.client_wait_mode_x3dh_key))
                        Connection_program.wait_mode_text.insert("end", "计算获得的密钥为:{}\n".format(Connection_program.client_wait_mode_x3dh_key))
                        # 进行密钥验证
                        # print("正在进行密钥验证...")
                        Connection_program.wait_mode_text.insert("end", "正在进行密钥验证...\n")
                        # 接收对方发送的验证消息
                        ensure_data = data_socket.recv(Connection_program.Max_data).decode()
                        # print("已接收到对方发送的验证消息为:{}".format(ensure_data))
                        Connection_program.wait_mode_text.insert("end", "已接收到对方发送的验证消息为:{}\n".format(ensure_data))
                        # 解密
                        clear_data = pysm4.decrypt_ecb(ensure_data, Connection_program.client_wait_mode_x3dh_key[0:15])
                        # print("解密验证消息后的明文为:{}".format(clear_data))
                        Connection_program.wait_mode_text.insert("end", "解密验证后明文为:{}\n".format(clear_data))
                        # 发送解密后的验证消息
                        data_socket.send(clear_data.encode())
                        # print("已发送解密后的验证消息，正在等待对方验证中...")
                        Connection_program.wait_mode_text.insert("end", "已发送解密后的验证消息，正在等待对方验证中...\n")
                        # 接收对方的回复结果
                        result_data = data_socket.recv(Connection_program.Max_data).decode()
                        if result_data == "OK":  # 判断对方的回复
                            # print("验证通过")
                            Connection_program.wait_mode_text.insert("end", "验证通过！\n")
                            data_socket.send("OK".encode())  # 通知服务端验证结果
                            Connection_program.wait_mode_send_button.config(state="normal")  # 消息发送按钮生效
                            Connection_program.wait_mode_connect_next_button.config(state="normal")  # 结束通信按钮生效
                            Connection_program.wait_mode_connect_state = 2  # 改变用户通信状态变量
                            Connection_program.client_wait_mode_connect_flag = True
                            # 初始化设置KDF，DH棘轮
                            File_program.init_x3dh_p_g()
                            Crypto_program.kdf_dh_other_new_time_public_key = other_public_key  # 对方身份公钥为 salt 输入
                            Crypto_program.kdf_chain_random_data = Connection_program.client_wait_mode_x3dh_key  # X3DH密钥为初始root key
                            test_data = Crypto_program.kdf_dh_encry_function("init")
                            data_socket.send(str(Crypto_program.kdf_dh_self_time_public_key).encode())  # 发送自己的临时公钥
                            time.sleep(0.1)
                            data_socket.send(test_data.encode())
                            # 改变组件相关参数
                            Connection_program.wait_mode_state_text.config(state="normal")
                            Connection_program.wait_mode_state_text.delete("1.0", "end")
                            Connection_program.wait_mode_state_text.insert("end", "当前处于通信状态")
                            Connection_program.wait_mode_state_text.config(state="disabled")
                            Connection_program.wait_mode_connect_close_button.config(state="disabled")
                            while True:  # 正常的加密通信阶段
                                talk_data = data_socket.recv(Connection_program.Max_data).decode()
                                if talk_data == "@client_wait_mode_active_this_connect_end":  # 判断通信是否为主动结束与对方的通信
                                    break
                                elif talk_data == "@client_wait_mode_passive_this_connect_end":   # 判断是否为对方结束通信
                                    data_socket.send("@sever_wait_mode_passive_this_connect_end".encode())  # 通知服务端本次通信结束
                                    Connection_program.ready_text.config(state="normal")
                                    Connection_program.ready_text.delete("1.0", "end")
                                    Connection_program.ready_text.insert("end", "对方已结束会话，本次通信结束，已返回等待模式")
                                    Connection_program.ready_text.config(state="disabled")
                                    break
                                else:
                                    # 此处加入双棘轮算法
                                    key_data = data_socket.recv(Connection_program.Max_data).decode()
                                    Crypto_program.kdf_dh_other_new_time_public_key = key_data
                                    talk_data = Crypto_program.kdf_dh_decry_function(talk_data)
                                    # print(other_name, ":", talk_data)
                                    Connection_program.wait_mode_text.insert("end", "{} : {}\n".format(other_name, talk_data))
                            # 改变容器内相应组件的参数设置
                            Connection_program.wait_mode_connect_next_button.config(state="disabled")  # 结束通信按钮失效
                            Connection_program.wait_mode_send_button.config(state="disabled")  # 消息发送按钮失效
                            Connection_program.wait_mode_connect_close_button.config(state="normal")  # 退出等待按钮生效
                            Connection_program.wait_mode_connect_state = 0  # 改变用户通信状态变量
                            Connection_program.client_wait_mode_connect_flag = False
                            # 改变状态显示
                            Connection_program.wait_mode_state_text.config(state="normal")
                            Connection_program.wait_mode_state_text.delete("1.0", "end")
                            Connection_program.wait_mode_state_text.insert("end", "当前处于等待模式")
                            Connection_program.wait_mode_state_text.config(state="disabled")
                        else:
                            data_socket.send("NO".encode())
                            # print("\033[91m验证失败\033[0m")
                            Connection_program.wait_mode_text.insert("end", "验证失败！\n")
                            Connection_program.client_wait_mode_connect_flag = False
                    else:
                        data_socket.send("NO".encode())
                        # print("\033[91m计算失败\033[0m")
                        Connection_program.wait_mode_text.insert("end", "计算失败！\n")
                        Connection_program.client_wait_mode_connect_flag = False
                else:
                    Connection_program.wait_mode_text.insert("end", "本次通信已结束!\n")
                    Connection_program.wait_mode_connect_state = 0
                    Connection_program.client_wait_mode_connect_flag = False
            else:
                Connection_program.wait_mode_send_button.config(state="disabled")  # 消息发送按钮失效
                Connection_program.wait_mode_connect_next_button.config(state="disabled")  # 结束通信按钮失效
                Connection_program.wait_mode_connect_start_button.config(state="normal")  # 进入等待模式按钮生效
                Connection_program.wait_mode_connect_close_button.config(state="normal")  # 结束等待模式按钮生效
                Connection_program.ready_text.config(state="normal")
                Connection_program.ready_text.delete("1.0", "end")
                Connection_program.ready_text.insert("end", "已退出等待模式")
                Connection_program.ready_text.config(state="disabled")
                Connection_program.wait_mode_state_text.config(state="normal")
                Connection_program.wait_mode_state_text.delete("1.0", "end")
                Connection_program.wait_mode_state_text.insert("end", "等待进入等待模式")
                Connection_program.wait_mode_state_text.config(state="disabled")
                break
        Connection_program.client_wait_mode_connect_flag = False
        Connection_program.client_wait_mode_flag = False
        # print("等待模式接收线程已结束")
        Connection_program.wait_mode_exit_button.config(state="normal")  # 退出按钮生效
        Connection_program.wait_mode_text.insert("end", "等待模式接收线程已结束！\n")

    # 注册界面
    @staticmethod
    def register_window():
        # 以下为界面参数
        # 初始化所需要的参数变量
        Connection_program.register_name = tk.StringVar()
        Connection_program.register_password_one = tk.StringVar()
        Connection_program.register_password_two = tk.StringVar()
        # 设置窗口参数
        Window_program.register_frame = tk.Frame(root_window, height=500, width=600, bd=3)
        Window_program.register_frame.place(anchor="center", relx=0.5, rely=0.5)
        # 就绪文本框
        Connection_program.ready_text = tk.Text(Window_program.register_frame, font=("黑体", 18), fg="red", height=1, width=40, padx=10, pady=5)
        Connection_program.ready_text.config(state="disabled")
        Connection_program.ready_text.grid(row=0, columnspan=2, padx=10, pady=10)

        # 提示语
        tk.Label(Window_program.register_frame, text="请输入数据以注册", font=("kaiti", 18), padx=10, pady=10).grid(row=1, columnspan=2, padx=10, pady=10)
        # 用户名
        tk.Label(Window_program.register_frame, text="账户名:", font=("黑体", 15), padx=10, pady=10).grid(row=2, column=0, padx=10, pady=10)
        tk.Entry(Window_program.register_frame, textvariable=Connection_program.register_name, font=("黑体", 13), width=23).grid(row=2, column=1, padx=10, pady=10)
        # 密码及确认
        tk.Label(Window_program.register_frame, text="密码:", font=("黑体", 15), padx=10, pady=10).grid(row=3, column=0, padx=10, pady=10)
        tk.Entry(Window_program.register_frame, textvariable=Connection_program.register_password_one, font=("黑体", 13), width=23).grid(row=3, column=1, padx=10, pady=10)
        tk.Label(Window_program.register_frame, text="确认密码:", font=("黑体", 15), padx=10, pady=10).grid(row=4, column=0, padx=10, pady=10)
        tk.Entry(Window_program.register_frame, textvariable=Connection_program.register_password_two, font=("黑体", 13), width=23).grid(row=4, column=1, padx=10, pady=10)
        # 注册
        Connection_program.register_button = (tk.Button(Window_program.register_frame, text="注册", font=("黑体", 15), relief="raised", fg="green", padx=5, pady=5, command=Connection_program.start_register_connect))
        Connection_program.register_button.grid(row=5, column=0, padx=10, pady=10)
        # 取消
        tk.Button(Window_program.register_frame, text="取消", font=("黑体", 15), relief="raised", fg="red", padx=5, pady=5, command=Connection_program.register_window_to_start_window).grid(row=5, column=1, padx=10, pady=10)

    # 开启通信的方法  注册模式
    @staticmethod
    def start_register_connect():
        end_flag = False
        next_flag = False
        # 请求发送预处理
        name = Connection_program.register_name.get()
        password_one = Connection_program.register_password_one.get()
        password_two = Connection_program.register_password_two.get()
        if name == "" or name == "用户名不能为空！":
            Connection_program.register_name.set("用户名不能为空！")
        else:
            if password_one == "" or password_one == "密码不能为空！":
                Connection_program.register_password_one.set("密码不能为空！")
            else:
                if Crypto_program.test_key_strong(password_one, 16):
                    if password_one != password_two:
                        Connection_program.register_password_two.set("密码不一致！")
                    else:
                        next_flag = True
                        Connection_program.register_button.config(state="disabled")  # 截止本次通信完成前，该按钮不再生效
                else:
                    Connection_program.register_password_one.set("密钥不合法或强度不够！")
        if next_flag is True:
            # 一旦启动，改变通信状态
            Connection_program.connect_flag = True
            # 通信部分
            IP = Connection_program.get_host_ip()  # 获得本机的IPV4地址
            PORT = Connection_program.PORT  # 设置端口号
            # 设置网络层协议，传输层协议
            data_socket = socket(AF_INET, SOCK_STREAM)  # IP协议，TCP
            # 尝试进行连接
            try:
                data_socket.connect((IP, PORT))
                # 接收随机验证消息
                random_data = data_socket.recv(Connection_program.Max_data).decode()
                # 发送验证消息
                sign_hash_data = SystemSign.system_sign_message(random_data)
                data_socket.send(sign_hash_data.encode())
                # print("正在尝试连接服务器...")
                Connection_program.ready_text.config(state="normal")
                Connection_program.ready_text.insert("end", "正在尝试连接服务器...")
                Connection_program.ready_text.config(state="disabled")
                # 接收验证结果
                result_data = data_socket.recv(Connection_program.Max_data).decode()
                if result_data == "OK":
                    # print("连接服务器成功")
                    Connection_program.ready_text.config(state="normal")
                    Connection_program.ready_text.delete("1.0", "end")
                    Connection_program.ready_text.insert("end", "连接服务器成功！正在发送注册请求中...")
                    Connection_program.ready_text.config(state="normal")
                    data_socket.send("@sever_connect_mode2".encode())  # 客户端向服务端发送请求用户注册指令
                    ok_flag = data_socket.recv(Connection_program.Max_data).decode()  # 客户端接收来自服务端的返回确认
                    if ok_flag == "OK":  # 判断返回结果
                        # 发送注册用户名
                        data_socket.send(name.encode())
                        # 接收服务端查询结果
                        flag = data_socket.recv(Connection_program.Max_data).decode()
                        Connection_program.ready_text.config(state="normal")
                        Connection_program.ready_text.delete("1.0", "end")
                        if flag == "OK":
                            hash_password = sm3.sm3_hash(func.bytes_to_list(password_two.encode()))  # 获得用户密码的哈希值
                            data_socket.send(hash_password.encode())  # 发送该哈希值至服务端
                            # 接收服务端接收结果
                            ok_flag = data_socket.recv(Connection_program.Max_data).decode()
                            # 调用用户已获得公钥数据文件生成的方法
                            ok_flg2 = File_program.create_client_get_key_list_file(name)
                            if ok_flag == "OK" and ok_flg2 is True:  # 判断复合返回结果
                                # print("注册成功")
                                Connection_program.ready_text.insert("end", "注册成功！")
                                end_flag = True
                            else:
                                # print("\033[91m 注册失败！\033[0m")
                                Connection_program.ready_text.insert("end", "注册失败！")
                        else:
                            # print("\033[91m 已存在相同用户名！\033[0m")
                            Connection_program.ready_text.insert("end", "已存在相同用户名！")
                            data_socket.send("@sever_client_create_exit".encode())  # 发送终止用户注册指令
                        Connection_program.ready_text.config(state="disabled")
                    else:
                        # print("\033[91m请求失败\033[0m")
                        Connection_program.ready_text.config(state="normal")
                        Connection_program.ready_text.delete("1.0", "end")
                        Connection_program.ready_text.insert("end", "请求失败！")
                        Connection_program.ready_text.config(state="disabled")
                else:
                    # print("\033[91连接服务器失败\033[0m")
                    Connection_program.ready_text.config(state="normal")
                    Connection_program.ready_text.delete("1.0", "end")
                    Connection_program.ready_text.insert("end", "连接服务器失败！")
                    Connection_program.ready_text.config(state="disabled")
            except ConnectionRefusedError:  # 检测连接状况
                Connection_program.ready_text.config(state="normal")
                Connection_program.ready_text.delete("1.0", "end")
                Connection_program.ready_text.insert("end", "服务器不在工作状态或维护中!")
                Connection_program.ready_text.config(state="disabled")
                Connection_program.register_button.config(state="normal")
            finally:
                # 关闭连接
                data_socket.close()
                Main_program.clear_screen()  # 清屏
                if end_flag is False:
                    Connection_program.register_button.config(state="normal")

    # 定义从注册界面返回初始界面的方法
    @staticmethod
    def register_window_to_start_window():
        Window_program.register_frame.destroy()
        Main_program.start_application()

    # 定义发送消息端的多线程的方法   弃用
    @staticmethod
    def send_data(data_socket):
        print("发送端线程已启用")
        while True:
            if Connection_program.connect_flag is False:
                data_socket.close()
                break
            # 等待用户输入发送消息
            data = input()
            if data == "结束" or data == "exit":
                data_socket.send("@client_connect_end".encode())
                Connection_program.connect_flag = False
                break
            else:
                data = Main_program.name + ":" + data
                data_socket.send(data.encode())
                # print("已发送消息{}".format(data))
        print("发送端线程已结束")

    # 定义接收消息端的多线程的方法   弃用
    @staticmethod
    def recv_data(data_socket):
        print("接收端线程已启用")
        while True:
            if Connection_program.connect_flag is False:
                data_socket.close()
                break
            data = data_socket.recv(Connection_program.Max_data).decode()
            print(data)
            if data == "结束" or data == "exit":
                Connection_program.connect_flag = False
                break
        print("接收端线程已结束")


# 创建p2p通信类
class Node_program(object):
    def __init__(self):
        super().__init__()

    # 服务节点固定参数
    sever_node_ip = "10.251.228.163"  # 由于在同一个计算机上进行的测试，故自动获取即可
    sever_node_port = 1111
    max_data = 4096
    sever_node_socket = ""  # 服务节点的通信体
    sever_node_connect_flag = False  # 服务节点是否连接的标志
    sever_node_free_flag = False  # 服务线程是否空闲的标志

    # 用户节点参数
    node_name = ""  # 节点名称
    node_password = ""  # 节点密码
    node_ip = ""  # 节点IP地址
    node_port = ""  # 节点端口
    node_public_key = ""  # 节点公钥
    node_private_key = ""  # 节点私钥
    node_blockchain_length = ""  # 节点含有的区块链长度
    node_balance = ""  # 节点的余额
    node_listen_max_num = 3  # 节点最多监听数量
    node_listen_now_num = 0  # 节点当前监听数量
    node_work_flag = False  # 节点开启状态
    node_close_able_flag = True  # 节点占用状态  决定节点当前是否可以关闭
    alive_other_node_socket_list = []  # 节点当前连接的其他节点数据列表 (包含服务节点)
    alive_other_node_name_list = []  # 节点当前连接的其他节点名数据列表
    alive_other_node_ip_list = []  # 节点当前连接的其他节点ip数据列表
    alive_other_node_port_list = []  # 节点当前连接的其他节点端口数据列表
    node_max_data = 4096

    ready_text = ""  # 通用提示文本框
    # 初始节点窗口组件参数
    node_open_button = ""  # 节点开启按钮
    node_create_button = ""  # 节点创建按钮

    # 创建节点界面组件参数以及其他参数
    name_entry = ""  # 节点名输入框
    name_var = ""
    password1_entry = ""  # 密码输入框
    password1_var = ""
    password2_entry = ""  # 密码确认框
    password2_var = ""
    ip_entry = ""   # ip输入框
    ip_var = ""
    port_entry = ""  # 端口输入框
    port_var = ""
    public_key_text = ""  # 公钥显示框
    private_key_text = ""  # 私钥显示框
    node_create_send_button = ""  # 创建按钮
    node_create_connect_flag = False  # 是否连接至服务节点的标志
    node_create_try_flag = False  # 尝试注册标志
    node_create_socket = ""  # 创建节点的通信体

    # 开启节点界面组件参数及其他参数
    node_open_name_var = ""  # 节点名
    node_open_password_var = ""  # 节点密码
    node_open_input_button = ""  # 节点开启按钮
    node_open_exit_button = ""  # 退出按钮

    # 节点主界面组件参数及其他
    alive_node_text = ""
    alive_node_update_flag = False
    # 节点主界面内置容器
    normal_node_main_in_frame = ""
    normal_node_block_chain_data_text = ""  # 区块链数据显示文本框

    # 挖矿界面参数和组件
    mine_work_show_detail_text = ""  # 挖矿具体数据显示窗口
    mine_work_target_hast_text = ""  # 目标哈希值显示框
    mine_work_target_random_num_text = ""  # 目标随机数显示框
    mine_work_start_button = ""  # 挖矿开启按钮
    mine_work_stop_button = ""  # 挖矿暂停按钮
    mine_work_exit_button = ""  # 退出挖矿按钮
    mine_work_stop_flag = False  # 挖矿暂停标志
    mine_work_exit_flag = False  # 挖矿停止标志
    mine_work_flag = False  # 挖矿工作状态
    mine_work_head_dict = ""  # 挖矿成功后保存的区块头字典
    mine_work_body_list = ""  # 挖矿成功后保存的区块体列表

    # 交易界面的组件参数及其他参数
    # 加密货币付款界面以及组件参数
    trading_sender_payee_entry = ""  # 收款方输入框
    trading_sender_payee_var = ""  # 收款输入变量
    trading_sender_amount_text = ""  # 金额显示文本
    trading_sender_amount_var = ""  # 金额输入变量
    trading_sender_password_entry = ""  # 密码输入栏
    trading_sender_password_var = ""  # 密码输入变量
    trading_sender_self_sign_text = ""  # 签名显示文本
    trading_sender_self_sign_button = ""  # 签名按钮
    trading_sender_target_sign_text = ""  # 收款方签名标签
    trading_sender_payment_button = ""  # 付款按钮
    trading_sender_exit_button = ""  # 退出按钮
    trading_sender_data_dict = {"type": "", "payer": "", "payee": "", "amount": "", "timestamp": "", "sign": ""}  # 包含支付数据的字典,数据依次为：交易类型，支付者，收款者，金额，时间戳，签名
    trading_sender_sign_flag = False  # 签名的标志，为真时才能付款

    # 文件操作界面组件参数以及其他参数
    logs_file_show_file_text = ""  # 文件显示文本框
    logs_file_input_target_file_entry = ""  # 文件输入栏
    logs_file_input_target_file_var = ""  # 文件输入变量
    logs_file_read_target_file_button = ""  # 读取目标文件的按钮
    logs_file_read_target_file_flag = False  # 是否读取了文件的标志
    logs_file_read_target_file_name = ""  # 当前展示的文件名
    logs_file_delete_target_file_button = ""  # 删除目标文件的按钮
    logs_file_create_file_entry = ""  # 创建文件输入栏
    logs_file_create_file_var = ""  # 创建文件输入变量
    logs_file_create_file_button = ""  # 创建文件按钮
    logs_file_exit_button = ""  # 退出文件操作界面
    logs_file_file_list = []  # 文件数据列表  格式： 文件名  文件大小  文件起始位置  文件终止位置
    logs_file_file_sum = ""  # 文件总数量
    logs_file_load_flag = False  # 文件是否读取成功的标志

    # 连接界面组件参数以及其他参数
    connect_data_show_text = ""  # 其他已获得节点数据的显示文本框
    connect_data_target_entry = ""  # 目标用户序号输入栏
    connect_data_target_var = ""  # 目标用户序号变量
    connect_data_connect_button = ""  # 连接指定目标的按钮
    connect_data_update_button = ""  # 已连接节点的更新按钮
    connect_data_exit_button = ""  # 已连接节点的退出按钮
    # 其他用户节点数据
    other_normal_node_name_list = []  # 其他用户节点名列表
    other_normal_node_public_key_list = []  # 其他用户节点公钥列表
    other_normal_node_ip_list = []  # 其他用户节点ip列表
    other_normal_node_port_list = []  # 其他用户节点端口列表
    other_normal_node_balance_list = []  # 其他用户节点余额列表

    # 节点模式的初始界面
    @staticmethod
    def node_init_window():
        # 创建初始界面容器
        Window_program.node_frame = tk.Frame(root_window, relief="raised", bd=3, height=600, width=400)
        Window_program.node_frame.place(anchor="center", relx=0.5, rely=0.5)

        # 文本提示框
        Node_program.ready_text = tk.Text(Window_program.node_frame, font=("黑体", 18), fg="red", width=40, height=2, bd=3, padx=10, pady=5)
        Node_program.ready_text.insert("end", "您已进入节点模式")
        Node_program.ready_text.grid(row=0, padx=10, pady=10)
        Node_program.ready_text.config(state="disabled")

        # 开启节点按钮
        Node_program.node_open_button = tk.Button(Window_program.node_frame, text="开启节点", fg="blue", font=('黑体', 15), anchor="center", padx=15, pady=10, command=Node_program.node_init_window_to_open_window)
        Node_program.node_open_button.grid(row=1, padx=10, pady=10)

        # 创建节点按钮
        Node_program.node_create_button = tk.Button(Window_program.node_frame, text="创建节点", fg="blue", font=('黑体', 15), anchor="center", padx=15, pady=10, command=Node_program.node_init_window_to_create_window)
        Node_program.node_create_button.grid(row=2, padx=10, pady=10)

        # 退出按钮
        tk.Button(Window_program.node_frame, text="退出", fg="red", font=('黑体', 15), anchor="center", padx=15, pady=10, command=Node_program.node_init_window_to_start_window).grid(row=3, padx=10, pady=10)

    # 以下是节点初始界面转向其他界面的方法
    # 由节点初始界面返回主程序初始界面的方法
    @staticmethod
    def node_init_window_to_start_window():
        Window_program.node_frame.destroy()
        Main_program.start_application()

    @staticmethod
    def node_init_window_to_create_window():
        Window_program.node_frame.destroy()
        Node_program.node_create_window()

    @staticmethod
    def node_init_window_to_open_window():
        Window_program.node_frame.destroy()
        Node_program.node_open_window()

    # 开启节点的界面
    @staticmethod
    def node_open_window():
        # 初始参数设置
        Node_program.node_open_name_var = tk.StringVar()
        Node_program.node_open_password_var = tk.StringVar()
        # 初始化设置界面参数与容器
        Window_program.node_open_frame = tk.Frame(root_window,  relief="raised", bd=3, height=600, width=400)
        Window_program.node_open_frame.place(anchor="center", relx=0.5, rely=0.5)

        # 提示文本框
        Node_program.ready_text = tk.Text(Window_program.node_open_frame,  font=("黑体", 18), fg="red", width=50, height=2, bd=3, padx=10, pady=5)
        Node_program.ready_text.insert("end", "请输入节点信息以开启节点")
        Node_program.ready_text.config(state="disabled")
        Node_program.ready_text.grid(row=0, column=0, columnspan=4, padx=5, pady=5)

        # 节点名输入框及标签
        tk.Label(Window_program.node_open_frame, text="节点名:", fg="black", font=('黑体', 15), anchor="center", padx=15, pady=10, ).grid(row=1, column=0, padx=5, pady=5)
        tk.Entry(Window_program.node_open_frame, width=40, fg="black", font=("黑体", 15), textvariable=Node_program.node_open_name_var).grid(row=1, column=1, columnspan=3, padx=5, pady=5)

        # 节点密码输入框及标签
        tk.Label(Window_program.node_open_frame, text="节点密码:", fg="black", font=('黑体', 15), anchor="center", padx=15, pady=10, ).grid(row=2, column=0, padx=5, pady=5)
        tk.Entry(Window_program.node_open_frame, width=40, fg="black", font=("黑体", 15), textvariable=Node_program.node_open_password_var, show="*").grid(row=2, column=1, columnspan=3, padx=5, pady=5)

        # 确定按钮
        Node_program.node_open_input_button = tk.Button(Window_program.node_open_frame, text="开启", fg="red", font=('黑体', 15), anchor="center", padx=15, pady=10, command=Node_program.node_open_trans)
        Node_program.node_open_input_button.grid(row=3, column=0, columnspan=2, padx=5, pady=5)

        # 退出按钮
        Node_program.node_open_exit_button = tk.Button(Window_program.node_open_frame, text="退出", fg="red", font=('黑体', 15), anchor="center", padx=15, pady=10, command=Node_program.node_open_window_to_node_init_window)
        Node_program.node_open_exit_button.grid(row=3, column=1, columnspan=2, padx=5, pady=5)

    # 由节点开启界面返回初始节点界面的方法
    @staticmethod
    def node_open_window_to_node_init_window():
        Window_program.node_open_frame.destroy()
        Node_program.node_init_window()

    # 开启节点的中继方法
    @staticmethod
    def node_open_trans():
        Node_program.node_open_input_button.config(state="disabled")
        Node_program.node_open_exit_button.config(state="disabled")
        th = threading.Thread(target=Node_program.node_open)
        th.start()

    # 节点开启按钮对应的方法
    @staticmethod
    def node_open():
        Node_program.ready_text.config(state="normal")
        name = Node_program.node_open_name_var.get()
        password = Node_program.node_open_password_var.get()
        pass_flag = True
        if name == "" or name == "节点名不可为空！":
            Node_program.node_open_name_var.set("节点名不可为空！")
            pass_flag = False
        if password == "" or password == "节点密码不可为空！":
            Node_program.ready_text.delete("1.0", "end")
            Node_program.ready_text.insert("end", "节点密码不可为空！")
            pass_flag = False
        if pass_flag is True:
            pass_flag = False
            Node_program.ready_text.delete("1.0", "end")
            if os.path.exists(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(name) + "_folder"):
                if os.path.exists(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(name) + "_folder\\" + str(name) + "_base_data.txt"):
                    if Node_file_program.normal_node_init_read(name):
                        try:
                            if password == pysm4.decrypt_ecb(Node_program.node_password, password):
                                Node_program.ready_text.insert("end", "通过！")
                                # 解密节点数据
                                Node_program.node_name = pysm4.decrypt_ecb(Node_program.node_name, password)
                                Node_program.node_password = password
                                Node_program.node_public_key = pysm4.decrypt_ecb(Node_program.node_public_key, password)
                                Node_program.node_private_key = pysm4.decrypt_ecb(Node_program.node_private_key, password)
                                Node_program.node_ip = pysm4.decrypt_ecb(Node_program.node_ip, password)
                                Node_program.node_port = pysm4.decrypt_ecb(Node_program.node_port, password)
                                Node_program.node_blockchain_length = pysm4.decrypt_ecb(Node_program.node_blockchain_length, password)
                                Node_program.node_balance = pysm4.decrypt_ecb(Node_program.node_balance, password)
                                pass_flag = True
                            else:
                                Node_program.ready_text.insert("end", "节点密码错误！")
                        except:
                            Node_program.ready_text.insert("end", "解密异常！")
                        finally:
                            pass
                    else:
                        Node_program.ready_text.insert("end", "节点数据读取异常！")
                else:
                    Node_program.ready_text.insert("end", "节点数据丢失！")
            else:
                Node_program.ready_text.insert("end", "本地不存在该节点数据！")
        Node_program.ready_text.config(state="normal")
        Node_program.node_open_exit_button.config(state="normal")
        Node_program.node_open_input_button.config(state="normal")
        if pass_flag is True:  # 判断验证结果
            Node_program.node_open_window_to_normal_node_main_window()

    # 开启界面转向节点主界面的方法
    @staticmethod
    def node_open_window_to_normal_node_main_window():
        Window_program.node_open_frame.destroy()
        Node_program.normal_node_main_window()

    # 节点主界面
    @staticmethod
    def normal_node_main_window():
        # 设置外置容器
        Window_program.normal_node_main_frame = tk.Frame(root_window, relief="raised", bd=3, height=600, width=400)
        Window_program.normal_node_main_frame.place(anchor="center", relx=0.5, rely=0.5,)

        # 左侧实时节点连接显示框以及提示标签
        tk.Label(Window_program.normal_node_main_frame, text="当前已连接的节点如下", font=("黑体", 18), fg="black", height=1, bd=3, padx=10, pady=5).grid(row=0, column=0, padx=5, pady=5)
        Node_program.alive_node_text = tk.Text(Window_program.normal_node_main_frame, font=("黑体", 10), fg="black", width=40, height=45, bd=3, padx=10, pady=5)
        Node_program.alive_node_text.grid(row=1, column=0, padx=5, pady=5)

        # 提示文本框
        Node_program.ready_text = tk.Text(Window_program.normal_node_main_frame, font=("黑体", 18), fg="red", width=50, height=4, bd=3, padx=10, pady=5)
        Node_program.ready_text.insert("end", "当前用户节点: {} 开启中...".format(Node_program.node_name))
        Node_program.ready_text.config(state="disabled")
        Node_program.ready_text.grid(row=0, column=1, padx=5, pady=5)

        # 设置内置容器
        Node_program.normal_node_main_in_frame = tk.Frame(Window_program.normal_node_main_frame, relief="raised", bd=3, height=600, width=600)
        Node_program.normal_node_main_in_frame.grid_propagate(0)
        Node_program.normal_node_main_in_frame.grid(row=1, column=1,)

        # 区块链显示按钮
        tk.Button(Node_program.normal_node_main_in_frame,  text="区块链", fg="blue", font=('黑体', 15), anchor="center", padx=15, pady=10, command=Node_program.show_block_chain_data).grid(padx=5, pady=5)

        # 挖矿按钮
        tk.Button(Node_program.normal_node_main_in_frame,  text="挖矿", fg="blue", font=('黑体', 15), anchor="center", padx=15, pady=10, command=Node_program.block_mine_window).grid(padx=5, pady=5)

        # 交易按钮
        tk.Button(Node_program.normal_node_main_in_frame,  text="交易", fg="blue", font=('黑体', 15), anchor="center", padx=15, pady=10, command=Node_program.trading_init_window).grid(padx=5, pady=5)

        # 连接按钮
        tk.Button(Node_program.normal_node_main_in_frame, text="连接", fg="blue", font=('黑体', 15), anchor="center", padx=15, pady=10, command=Node_program.connect_data_window).grid(padx=5, pady=5)

        # 文件按钮
        tk.Button(Node_program.normal_node_main_in_frame, text="文件", fg="blue", font=('黑体', 15), anchor="center", padx=15, pady=10, command=Node_program.node_logs_file_window).grid(padx=5, pady=5)

        # 退出按钮
        tk.Button(Node_program.normal_node_main_in_frame,  text="退出", fg="red", font=('黑体', 15), anchor="center", padx=15, pady=10, command=Node_program.normal_node_window_to_node_init_window).grid(padx=5, pady=5)

        # 调用用户节点开启连接的方法
        Node_program.node_work_flag = True
        th = threading.Thread(target=Node_program.node_rever_start)
        th.start()
        # 调用正连接的节点实时显示的线程方法
        th = threading.Thread(target=Node_program.show_alive_node)
        th.start()
        # 默认连接服务节点的线程方法
        th = threading.Thread(target=Node_program.connect_sever_node_tcb)
        th.start()

    # 默认连接服务节点的线程开启方法
    @staticmethod
    def connect_sever_node_tcb():
        connect_flag = True  # 连接至服务节点的标志
        IP = Connection_program.get_host_ip()  # 设置目标ip
        PORT = Node_program.sever_node_port  # 设置端口号
        # 设置网络层协议，传输层协议
        data_socket = socket(AF_INET, SOCK_STREAM)  # IP协议，TCP
        # 尝试进行连接
        try:
            data_socket.connect((IP, PORT))
        except ConnectionRefusedError:
            data_socket.close()
            connect_flag = False
        finally:
            Node_program.ready_text.config(state="normal")
            # Node_program.ready_text.delete("1.0", "end")
            if connect_flag is True:
                data_socket.send("@sever_node_node_login".encode())
                data = data_socket.recv(Node_program.max_data).decode()
                if data == "OK":
                    data_socket.send(str(Node_program.node_name).encode())
                    if data_socket.recv(Node_program.max_data).decode() == "OK":
                        en_data = data_socket.recv(Node_program.max_data).decode()
                        node_sm2_crypto = sm2.CryptSM2(Node_program.node_private_key, Node_program.node_public_key)
                        data = Crypto_program.sm2_decrypt(node_sm2_crypto, en_data)
                        data_socket.send(data.encode())
                        if data_socket.recv(Node_program.max_data).decode() == "OK":
                            Node_program.ready_text.insert("end", "已连接至服务节点\n")
                            Node_program.alive_other_node_socket_list.append(data_socket)
                            Node_program.alive_other_node_name_list.append("SEVER")
                            Node_program.alive_other_node_ip_list.append(str(IP))
                            Node_program.alive_other_node_port_list.append(str(PORT))
                            Node_program.alive_node_update_flag = True
                            Node_program.sever_node_connect_flag = True  # 服务节点连接标志改变
                            Node_program.sever_node_socket = data_socket
                            # 调用服务节点接收线程
                            Node_program.sever_node_alive_tcb(data_socket)
                        else:
                            Node_program.ready_text.insert("end", "节点公私钥检验失败！\n")
                            data_socket.close()
                    else:
                        Node_program.ready_text.insert("end", "服务节点识别失败\n")
                        data_socket.close()
                else:
                    Node_program.ready_text.insert("end", "请求失败！\n")
                    data_socket.close()
            else:
                Node_program.ready_text.insert("end", "无法连接至服务节点！\n")
                Node_program.ready_text.config(state="disabled")
                return False

    # 处理服务节点的线程方法
    @staticmethod
    def sever_node_alive_tcb(data_socket):
        Node_program.sever_node_free_flag = False
        while True:
            data = data_socket.recv(Node_program.max_data).decode()
            if data == "@normal_node_other_break":  # 中断该线程
                break
            elif data == "@normal_node_new_trading":  # 验证新交易
                Node_program.recv_sever_node_trading_verify(data_socket)
            elif data == "@normal_node_new_block":  # 验证新区块
                pass

        Node_program.sever_node_free_flag = True

    # 接收交易并验证的方法
    @staticmethod
    def recv_sever_node_trading_verify(data_socket):
        Node_program.sever_node_free_flag = True
        data_socket.send("@sever_node_change_ability".encode())
        data_socket.recv(Node_program.max_data)  # 接收
        data_socket.recv(Node_program.max_data)
        trading_type = data_socket.recv(Node_program.max_data).decode()  # 接收交易类型
        if trading_type == "@normal_node_trading_one":
            payer = data_socket.recv(Node_program.max_data).decode()  # 接收付款节点
            payee = data_socket.recv(Node_program.max_data).decode()  # 接收收款节点
            amount = data_socket.recv(Node_program.max_data).decode()  # 接收金额
            timestamp = data_socket.recv(Node_program.max_data).decode()  # 接收时间戳
            sign = data_socket.recv(Node_program.max_data).decode()  # 接收付款方签名
            # 组合交易字典
            data_dict = {"type": "1", "payer": payer, "payee": payee, "amount": amount, "timestamp": timestamp, "sign": sign}
            # 调用节点余额处理的方法
            if Block_program.verify_node_trading_data(data_dict, "1"):
                data_socket.send("OK".encode())
            else:
                data_socket.send("FALSE".encode())
        else:
            payer = data_socket.recv(Node_program.max_data).decode()  # 接收付款节点
            payee = data_socket.recv(Node_program.max_data).decode()  # 接收收款节点
            amount = data_socket.recv(Node_program.max_data).decode()  # 接收金额
            timestamp = data_socket.recv(Node_program.max_data).decode()  # 接收时间戳
            payer_sign = data_socket.recv(Node_program.max_data).decode()  # 接收付款方签名
            payee_sign = data_socket.recv(Node_program.max_data).decode()  # 接收收款方签名
            # 组合交易字典
            data_dict = {"type": "1", "payer": payer, "payee": payee, "amount": amount, "timestamp": timestamp, "payer_sign": payer_sign, "payee_sign": payee_sign}
            # 调用节点余额处理的方法
            if Block_program.verify_node_trading_data(data_dict, "2"):
                data_socket.send("OK".encode())
            else:
                data_socket.send("FALSE".encode())
        # 返回调用接收的线程
        Node_program.sever_node_alive_tcb(data_socket)

    # 用户节点接收开启的方法
    @staticmethod
    def node_rever_start():
        Node_program.ready_text.config(state="normal")
        Node_program.ready_text.delete("1.0", "end")
        Node_program.ready_text.insert("end", "节点：{}，监听已开启\n".format(Node_program.node_name))
        listenSocket = socket(AF_INET, SOCK_STREAM)  # IP协议，TCP
        listenSocket.bind((Connection_program.get_host_ip(), int(Node_program.node_port)))  # 绑定地址和端口
        while Node_program.node_work_flag:
            while Node_program.node_listen_now_num <= Node_program.node_listen_max_num:
                # 设置监听
                listenSocket.listen(Node_program.node_listen_max_num)
                # 开启监听
                data_socket, addr = listenSocket.accept()
                Node_program.ready_text.config(state="normal")
                Node_program.ready_text.insert("end", "连接到来自ip:{},端口:{}".format(addr[0], addr[1]))
                Node_program.alive_other_node_socket_list.append(data_socket)
                Node_program.alive_other_node_name_list.append("NONE"+addr[1])
                Node_program.alive_other_node_ip_list.append(addr[0])
                Node_program.alive_other_node_port_list.append(addr[1])
                Node_program.alive_node_update_flag = True
                th = threading.Thread(target=Node_program.other_node_recv_tcb, args=(data_socket, addr[0], addr[1], ))
                th.start()
        listenSocket.close()

    # 实时更新当前已连接节点的线程方法
    @staticmethod
    def show_alive_node():
        Node_program.alive_node_text.insert("end", "节点名".ljust(10) + "节点ip".ljust(16) + "节点端口".ljust(5) + "\n")
        for i in range(0, Node_program.node_listen_now_num):
            Node_program.alive_node_text.insert("end", Node_program.alive_other_node_name_list[i].ljust(13) + Node_program.alive_other_node_ip_list[i].ljust(18) + Node_program.alive_other_node_port_list[i].ljust(5) + "\n")  # 节点数据
        while True:
            if Node_program.alive_node_update_flag is False:  # 判断当前是否需要更新节点数据
                pass
            else:
                Node_program.alive_node_update_flag = False
                Node_program.alive_node_text.delete("1.0", "end")
                Node_program.alive_node_text.insert("end", "节点名".ljust(10) + "节点ip".ljust(16) + "节点端口".ljust(5) + "\n")
                num = len(Node_program.alive_other_node_name_list)
                for i in range(0, num):
                    Node_program.alive_node_text.insert("end", str(Node_program.alive_other_node_name_list[i]).ljust(13) + str(Node_program.alive_other_node_ip_list[i]).ljust(18) + str(Node_program.alive_other_node_port_list[i]).ljust(5) + "\n")
            if Node_program.node_work_flag is False:  # 判断当前是否结束线程
                break

    # 接收并处理其他节点的线程方法  (可拓展，如加入验证机制等)
    @staticmethod
    def other_node_recv_tcb(data_socket, ip, port):
        # 更新连接节点显示列表
        Node_program.alive_other_node_socket_list.append(data_socket)
        Node_program.alive_other_node_name_list.append("NONE{}".format(port))
        Node_program.alive_other_node_ip_list.append(ip)
        Node_program.alive_other_node_port_list.append(port)
        Node_program.alive_node_update_flag = True
        # 接收标志信息
        data = data_socket.recv(Node_program.node_max_data).decode()
        if data == "@normal_node_active_connect":  # 判断该节点的连接类型
            Node_program.active_other_node_tcb(data_socket, "NONE{}".format(port), ip, port)
        elif data == "@normal_node_silence_connect":
            Node_program.silence_other_node_tcb(data_socket, "NONE{}".format(port), ip, port)
        else:
            data_socket.send("@normal_error_exit".encode())
            data_socket.close()
            # 更新连接节点显示列表
            Node_program.alive_other_node_socket_list.remove(data_socket)
            Node_program.alive_other_node_name_list.remove("NONE{}".format(port))
            Node_program.alive_other_node_ip_list.remove(ip)
            Node_program.alive_other_node_port_list.remove(port)
            Node_program.alive_node_update_flag = True

    # 活跃连接对应的线程
    @staticmethod
    def active_other_node_tcb(data_socket, name, ip, port):
        data_socket.send("OK".encode())
        pass

    # 沉默连接对应的线程
    @staticmethod
    def silence_other_node_tcb(data_socket, name, ip, port):
        data_socket.send("OK".encode())
        pass

    # 恢复内置容器初始组件的方法
    @staticmethod
    def recover_normal_node_main_in_frame():
        # 首先销毁容器内当前的数据
        Window_program.clear_frame(Node_program.normal_node_main_in_frame)
        # 区块链显示按钮
        tk.Button(Node_program.normal_node_main_in_frame, text="区块链", fg="blue", font=('黑体', 15), anchor="center", padx=15, pady=10, command=Node_program.show_block_chain_data).grid(padx=5, pady=5)

        # 挖矿按钮
        tk.Button(Node_program.normal_node_main_in_frame, text="挖矿", fg="blue", font=('黑体', 15), anchor="center", padx=15, pady=10, command=Node_program.block_mine_window).grid(padx=5, pady=5)

        # 交易按钮
        tk.Button(Node_program.normal_node_main_in_frame, text="交易", fg="blue", font=('黑体', 15), anchor="center", padx=15, pady=10, command=Node_program.trading_init_window).grid(padx=5, pady=5)

        # 连接按钮
        tk.Button(Node_program.normal_node_main_in_frame, text="连接", fg="blue", font=('黑体', 15), anchor="center", padx=15, pady=10, command=Node_program.connect_data_window).grid(padx=5, pady=5)

        # 日志按钮
        tk.Button(Node_program.normal_node_main_in_frame, text="文件", fg="blue", font=('黑体', 15), anchor="center", padx=15, pady=10, command=Node_program.node_logs_file_window).grid(padx=5, pady=5)

        # 退出按钮
        tk.Button(Node_program.normal_node_main_in_frame, text="退出", fg="red", font=('黑体', 15), anchor="center", padx=15, pady=10, command=Node_program.normal_node_window_to_node_init_window).grid(padx=5, pady=5)

    # 区块链数据显示的方法
    @staticmethod
    def show_block_chain_data():
        # 清空内置容器内组件
        Window_program.clear_frame(Node_program.normal_node_main_in_frame)
        # 添加组件
        tk.Label(Node_program.normal_node_main_in_frame, font=("黑体", 18), fg="black", bd=3, padx=10, pady=5, text="当前区块链数据如下").grid(row=0, column=0, columnspan=2, padx=5, pady=5)
        # 区块链显示数据文本框
        Node_program.normal_node_block_chain_data_text = tk.Text(Node_program.normal_node_main_in_frame, font=("黑体", 10), fg="black", width=75, height=35, bd=3, padx=10, pady=5, )
        Node_program.normal_node_block_chain_data_text.grid(row=1, column=0, columnspan=2, padx=5, pady=5)
        # 刷新按钮  再一次读取区块链数据以更新当前区块链数据
        tk.Button(Node_program.normal_node_main_in_frame, text="刷新", fg="green", font=('黑体', 15), anchor="center", padx=15, pady=10, command=Node_program.block_chain_data_update_function).grid(row=2, column=0, padx=5, pady=5)
        # 退出按钮
        tk.Button(Node_program.normal_node_main_in_frame, text="退出", fg="red", font=('黑体', 15), anchor="center", padx=15, pady=10, command=Node_program.recover_normal_node_main_in_frame).grid(row=2, column=1, padx=5, pady=5)
        # 调用读取并显示区块链数据的方法
        Node_file_program.block_chain_data_read_and_show(Node_program.node_name)

    # 区块链数据显示更新按钮对应的方法
    @staticmethod
    def block_chain_data_update_function():
        Node_program.ready_text.config(state="normal")
        Node_program.ready_text.delete("1.0", "end")
        if os.path.exists(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(Node_program.node_name) + r"_folder\block_chain_data"):
            Node_program.ready_text.insert('end', "刷新中...")
            # 清除当前区块链显示文本框中的数据
            Node_program.normal_node_block_chain_data_text.config(state="normal")
            Node_program.normal_node_block_chain_data_text.delete("1.0", "end")
            # 重新读取区块链数据
            Node_file_program.block_chain_data_read_and_show(Node_program.node_name)
        else:
            Node_program.ready_text.insert("end", "刷新失败！")

    # 挖矿界面的显示方法
    @staticmethod
    def block_mine_window():
        # 设置初始参数
        Node_program.mine_work_stop_flag = False  # 挖矿暂停标志
        Node_program.mine_work_exit_flag = False  # 挖矿停止标志
        Node_program.mine_work_flag = False  # 挖矿工作状态
        # 销毁内置容器的组件
        Window_program.clear_frame(Node_program.normal_node_main_in_frame)
        # 设置容器内的组件
        # 挖矿数据显示框以及标签
        tk.Label(Node_program.normal_node_main_in_frame, font=("黑体", 18), fg="black", bd=3, padx=10, pady=5, text="当前处于挖矿模块").grid(row=0, column=0, columnspan=3, padx=5, pady=5)
        Node_program.mine_work_show_detail_text = tk.Text(Node_program.normal_node_main_in_frame, font=("黑体", 10), fg="red", width=80, height=25, bd=3, padx=5, pady=5)
        Node_program.mine_work_show_detail_text.config(state="disabled")
        Node_program.mine_work_show_detail_text.grid(row=1, column=0, columnspan=3, padx=5, pady=5)
        # 目标哈希显示框以及提示标签
        tk.Label(Node_program.normal_node_main_in_frame, text="结果哈希值:", font=("黑体", 15), fg="black", height=1, bd=3, padx=5, pady=5).grid(row=2, column=0, padx=5, pady=5)
        Node_program.mine_work_target_hast_text = tk.Text(Node_program.normal_node_main_in_frame, font=("黑体", 10), fg="red", width=60, height=1, bd=3, padx=10, pady=5)
        Node_program.mine_work_target_hast_text.config(state="disabled")
        Node_program.mine_work_target_hast_text.grid(row=2, column=1, columnspan=2, padx=5, pady=5)
        # 目标随机数显示框以及标签
        tk.Label(Node_program.normal_node_main_in_frame, text="结果随机数:", font=("黑体", 15), fg="black", height=1, bd=3, padx=5, pady=5).grid(row=3, column=0, padx=5, pady=5)
        Node_program.mine_work_target_random_num_text = tk.Text(Node_program.normal_node_main_in_frame, font=("黑体", 10), fg="red", width=60, height=1, bd=3, padx=10, pady=5)
        Node_program.mine_work_target_random_num_text.config(state="disabled")
        Node_program.mine_work_target_random_num_text.grid(row=3, column=1, columnspan=2, padx=5, pady=5)
        # 挖矿开启按钮
        Node_program.mine_work_start_button = tk.Button(Node_program.normal_node_main_in_frame, text="开始", fg="green", font=('黑体', 15), anchor="center", padx=15, pady=10, command=Node_program.block_main_trans)
        Node_program.mine_work_start_button.grid(row=4, column=0, padx=5, pady=5)
        # 挖矿暂停按钮
        Node_program.mine_work_stop_button = tk.Button(Node_program.normal_node_main_in_frame, text="暂停/恢复", fg="red", font=('黑体', 15), anchor="center", padx=15, pady=10, command=Node_program.mine_work_stop_or_recover_function)
        Node_program.mine_work_stop_button.config(state="disabled")
        Node_program.mine_work_stop_button.grid(row=4, column=1, padx=5, pady=5)
        # 退出挖矿按钮
        Node_program.mine_work_exit_button = tk.Button(Node_program.normal_node_main_in_frame, text="退出", fg="red", font=('黑体', 15), anchor="center", padx=15, pady=10, command=Node_program.mine_work_exit_function)
        Node_program.mine_work_exit_button.grid(row=4, column=2, padx=5, pady=5)

    # 挖矿线程的中继方法
    @staticmethod
    def block_main_trans():
        # 改变组件的参数
        Node_program.mine_work_start_button.config(state="disabled")  # 开始按钮失效
        Node_program.mine_work_stop_button.config(state="normal")  # 暂停/恢复按钮生效
        Node_program.mine_work_exit_button.config(state="disabled")  # 挖矿一旦开始，只有暂停时可以退出
        Node_program.mine_work_flag = True  # 改变挖矿状态标志符
        # 启用挖矿线程
        th = threading.Thread(target=Block_program.block_mine)
        th.start()

    # 挖矿暂停/恢复按钮对应的方法
    @staticmethod
    def mine_work_stop_or_recover_function():
        Node_program.ready_text.config(state="normal")
        Node_program.ready_text.delete("1.0", "end")
        if Node_program.mine_work_stop_flag is False:
            Node_program.mine_work_stop_flag = True
            Node_program.ready_text.insert("end", "挖矿已暂停")
        else:
            Node_program.mine_work_stop_flag = False
            Node_program.ready_text.insert("end", "挖矿已恢复")
        Node_program.ready_text.config(state="disabled")

    # 挖矿退出按钮对应的中继方法
    @staticmethod
    def mine_work_exit_function():
        if Node_program.mine_work_flag is True:
            flag = tk.messagebox.askyesno(title='退出挖矿？', message='挖矿进行中，是否退出？')  # 信息确认弹窗 是 Ture或 否 False
            if flag is True:  # 判断选择结果
                Node_program.mine_work_exit_flag = True
                Node_program.recover_normal_node_main_in_frame()
        else:
            Node_program.recover_normal_node_main_in_frame()

    # 交易的初始界面方法
    @staticmethod
    def trading_init_window():
        # 销毁当前内置容器内的所有组件
        Window_program.clear_frame(Node_program.normal_node_main_in_frame)
        # 提示标签语
        tk.Label(Node_program.normal_node_main_in_frame, text="交易界面", font=("黑体", 15), fg="black", height=1, bd=3, padx=5, pady=5, ).grid(padx=5, pady=5)

        # 加密货币按钮
        tk.Button(Node_program.normal_node_main_in_frame, text="加密货币付款", fg="blue", font=('黑体', 15), anchor="center", padx=15, pady=10, command=Node_program.trading_sender_window).grid(padx=5, pady=5)

        # 普通交易按钮
        tk.Button(Node_program.normal_node_main_in_frame, text="普通交易", fg="red", font=('黑体', 15), anchor="center", padx=15, pady=10,).grid(padx=5, pady=5)

        # 退出按钮
        tk.Button(Node_program.normal_node_main_in_frame, text="退出", fg="red", font=('黑体', 15), anchor="center", padx=15, pady=10, command=Node_program.recover_normal_node_main_in_frame).grid(padx=5, pady=5)

        # 调用读取其他用户节点数据的方法
        if Node_file_program.read_other_normal_node_data():
            pass
        else:
            Node_program.ready_text.config(state="disabled")
            Node_program.ready_text.delete("1.0", "end")
            Node_program.ready_text.insert("end", "其他用户节点数据文件读取异常，当前无法交易！")

    # 加密货币付款界面
    @staticmethod
    def trading_sender_window():
        # 销毁当前内置容器内的所有组件
        Window_program.clear_frame(Node_program.normal_node_main_in_frame)
        # 初始设置变量参数
        Node_program.trading_sender_payee_var = tk.StringVar()
        Node_program.trading_sender_amount_var = tk.StringVar()
        Node_program.trading_sender_password_var = tk.StringVar()

        # 界面提示标签
        tk.Label(Node_program.normal_node_main_in_frame, text="交易界面->加密货币付款", font=("黑体", 15), fg="black", height=1, width=50, bd=3, padx=5, pady=5, ).grid(row=0, column=0, columnspan=3, padx=5, pady=5)

        # 收款方文本框以及标签
        tk.Label(Node_program.normal_node_main_in_frame, text="收款方:", font=("黑体", 15), fg="black", height=1, bd=3, padx=5, pady=5, ).grid(row=1, column=0, padx=5, pady=5)
        Node_program.trading_sender_payee_entry = tk.Entry(Node_program.normal_node_main_in_frame, textvariable=Node_program.trading_sender_payee_var, width=40, font=("黑体", 15), fg="black", bd=3, )
        Node_program.trading_sender_payee_entry.grid(row=1, column=1, columnspan=2, padx=5, pady=5)

        # 金额文本框以及标签
        tk.Label(Node_program.normal_node_main_in_frame, text="金额:", font=("黑体", 15), fg="black", height=1, bd=3, padx=5, pady=5, ).grid(row=2, column=0, padx=5, pady=5)
        Node_program.trading_sender_amount_entry = tk.Entry(Node_program.normal_node_main_in_frame, textvariable=Node_program.trading_sender_amount_var, width=40, font=("黑体", 15), fg="black", bd=3, )
        Node_program.trading_sender_amount_entry.grid(row=2, column=1, columnspan=2, padx=5, pady=5)

        # 密码文本框以及标签
        tk.Label(Node_program.normal_node_main_in_frame, text="密码:", font=("黑体", 15), fg="black", height=1, bd=3, padx=5, pady=5, ).grid(row=3, column=0, padx=5, pady=5)
        Node_program.trading_sender_password_entry = tk.Entry(Node_program.normal_node_main_in_frame, textvariable=Node_program.trading_sender_password_var, show="*", width=40, font=("黑体", 15), fg="black", bd=3,)
        Node_program.trading_sender_password_entry.grid(row=3, column=1, columnspan=2, padx=5, pady=5)

        # 自己签名的按钮以及文本框
        Node_program.trading_sender_self_sign_button = tk.Button(Node_program.normal_node_main_in_frame, text="签名", font=("黑体", 15), fg="black", bd=3, padx=5, pady=5, command=Node_program.trading_one_sign_function)
        Node_program.trading_sender_self_sign_button.grid(row=4, column=0, padx=5, pady=5)
        Node_program.trading_sender_self_sign_text = tk.Text(Node_program.normal_node_main_in_frame, font=("黑体", 15), fg="black", height=5, width=40, bd=3, padx=5, pady=5, )
        Node_program.trading_sender_self_sign_text.config(state="disabled")
        Node_program.trading_sender_self_sign_text.grid(row=4, column=1, columnspan=2, padx=5, pady=5)

        # 对方签名的文本框
        """
        tk.Label(Node_program.normal_node_main_in_frame, ).grid()
        Node_program.trading_sender_target_sign_text = tk.Text(Node_program.normal_node_main_in_frame, )
        Node_program.trading_sender_target_sign_text.grid()
        """

        # 付款按钮
        Node_program.trading_sender_payment_button = tk.Button(Node_program.normal_node_main_in_frame, text="付款", font=("黑体", 15), fg="green",  bd=3, padx=5, pady=5, command=Node_program.trading_one_payment_function)
        Node_program.trading_sender_payment_button.grid(row=5, column=0, padx=5, pady=5)

        # 数据重置按钮
        tk.Button(Node_program.normal_node_main_in_frame, text="重置", font=("黑体", 15), fg="green",  bd=3, padx=5, pady=5, command=Node_program.trading_one_resetting_function).grid(row=5, column=1, padx=5, pady=5)

        # 退出按钮
        Node_program.trading_sender_exit_button = tk.Button(Node_program.normal_node_main_in_frame, text="退出", font=("黑体", 15), fg="red",  bd=3, padx=5, pady=5, command=Node_program.recover_normal_node_main_in_frame)
        Node_program.trading_sender_exit_button.grid(row=5, column=2, padx=5, pady=5)

    # 签名按钮对应的方法
    @staticmethod
    def trading_one_sign_function():
        # 按钮点击后即失效
        Node_program.trading_sender_self_sign_button.config(state="disabled")
        Node_program.ready_text.config(state="normal")
        Node_program.ready_text.delete("1.0", "end")
        # 获得当前填入的数据
        payee = Node_program.trading_sender_payee_var.get()  # 收款方
        amount = Node_program.trading_sender_amount_var.get()  # 金额
        try:
            amount = int(amount)
            password = Node_program.trading_sender_password_var.get()  # 密码
            if str(payee) in Node_program.other_normal_node_name_list:  # 判断收款方是否存在
                if amount <= int(Node_program.node_balance):  # 判断余额是否足够
                    if password == Node_program.node_password:
                        timestamp = time.time()
                        data = "1" + str(Node_program.node_name) + payee + str(amount) + str(timestamp)  # 交易类型  付款方节点名  收款方节点名  金额 时间戳
                        hash_data = sm3.sm3_hash(func.bytes_to_list(data.encode()))
                        sm2_crypto = sm2.CryptSM2(Node_program.node_private_key, Node_program.node_public_key)
                        sign_data = sm2_crypto.sign(hash_data.encode(), str(len(payee)))
                        Node_program.ready_text.insert("end", "签名完成！\n")
                        # 显示签名数据
                        Node_program.trading_sender_self_sign_text.config(state="normal")
                        Node_program.trading_sender_self_sign_text.insert("end", sign_data)
                        Node_program.trading_sender_self_sign_text.config(state="disabled")
                        # 改变签名标志
                        Node_program.trading_sender_sign_flag = True
                        # 组合字典
                        Node_program.trading_sender_data_dict["type"] = "1"  # 交易类型
                        Node_program.trading_sender_data_dict["payer"] = str(Node_program.node_name)  # 收款方
                        Node_program.trading_sender_data_dict["payee"] = str(payee)  # 付款方
                        Node_program.trading_sender_data_dict["amount"] = str(amount)  # 金额
                        Node_program.trading_sender_data_dict["timestamp"] = str(timestamp)  # 时间戳
                        Node_program.trading_sender_data_dict["sign"] = str(sign_data)  # 签名(付款方)
                    else:
                        Node_program.ready_text.insert("end", "密码错误！")
                        Node_program.trading_sender_self_sign_button.config(state="normal")
                else:
                    Node_program.ready_text.insert("end", "余额不足！")
                    Node_program.trading_sender_self_sign_button.config(state="normal")
            else:
                Node_program.ready_text.insert("end", "收款方异常！")
                Node_program.trading_sender_self_sign_button.config(state="normal")
        except ValueError:
            Node_program.ready_text.insert("end", "输入异常！")
            Node_program.trading_sender_self_sign_button.config(state="normal")
        finally:
            pass

    # 付款按钮的方法
    @staticmethod
    def trading_one_payment_function():
        Node_program.ready_text.config(state="normal")
        if Node_program.trading_sender_sign_flag is True:  # 检测是否已经签名
            Node_program.ready_text.delete("1.0", "end")
            # 提示框显示
            if tk.messagebox.askyesno(title='确认付款？', message='是否支付？'):  # 信息确认弹窗 是 Ture或 否 False
                Node_program.ready_text.insert("end", "支付成功！\n")
                Node_program.trading_sender_payment_button.config(state="disabled")  # 付款成功后按钮即失效
                # 调用广播的方法
                th = threading.Thread(target=Node_program.trading_one_spread_trading)
                th.start()
            else:
                Node_program.ready_text.insert("end", "付款已取消")
        else:
            Node_program.ready_text.delete("1.0", "end")
            Node_program.ready_text.insert("end", "签名后才能付款！\n")

    # 调用广播交易的线程方法
    @staticmethod
    def trading_one_spread_trading():
        Node_program.trading_sender_exit_button.config(state="disabled")
        Node_program.ready_text.insert("end", "请稍等，交易广播中...\n")
        # 判断是否已连接至服务节点
        if Node_program.sever_node_connect_flag is True:
            if Node_program.sever_node_free_flag is False:
                Node_program.sever_node_socket.send("@sever_node_change_ability".encode())
                while True:
                    if Node_program.sever_node_free_flag is True:
                        break
                data = Node_program.sever_node_socket.recv(Node_program.max_data).decode()
                if data == "@normal_node_verify_tcb":
                    # 发交易请求与数据
                    Node_program.sever_node_socket.send("@sever_node_trading_mode".encode())
                    time.sleep(1)
                    Node_program.sever_node_socket.send("@sever_node_trading_one".encode())  # 发送交易类型
                    time.sleep(1)
                    Node_program.sever_node_socket.send(str(Node_program.trading_sender_data_dict["payer"]).encode())  # 付款方
                    time.sleep(1)
                    Node_program.sever_node_socket.send(str(Node_program.trading_sender_data_dict["payee"]).encode())  # 收款方
                    time.sleep(1)
                    Node_program.sever_node_socket.send(str(Node_program.trading_sender_data_dict["amount"]).encode())  # 金额
                    time.sleep(1)
                    Node_program.sever_node_socket.send(str(Node_program.trading_sender_data_dict["timestamp"]).encode())  # 交易时间
                    time.sleep(1)
                    Node_program.sever_node_socket.send(str(Node_program.trading_sender_data_dict["sign"]).encode())  # 付款方签名
                    # 接收服务节点判断结果
                    data = Node_program.sever_node_socket.recv(Node_program.max_data).decode()
                    Node_program.ready_text.config(state="normal")
                    if data == "OK":
                        Node_program.ready_text.insert("end", "服务节点认证成功，您的交易即将上链\n")
                    else:
                        Node_program.ready_text.insert("end", "服务节点认证失败！\n")
                    # 返回调用接收模式的线程
                    th = threading.Thread(target=Node_program.sever_node_alive_tcb, args=(Node_program.sever_node_socket, ))
                    th.start()
                else:
                    Node_program.ready_text.insert("end", "切换至广播线程异常！")
            else:
                Node_program.ready_text.insert('end', "当前繁忙，无法广播")
        else:
            Node_program.ready_text.insert("end", "暂未连接服务节点，无法广播交易!")
        Node_program.trading_sender_exit_button.config(state="normal")

    # 加密货币付款 重置按钮的方法
    @staticmethod
    def trading_one_resetting_function():
        # 重置数据
        Node_program.trading_sender_payee_var.set("")  # 收款方
        Node_program.trading_sender_amount_var.set("")  # 金额
        Node_program.trading_sender_password_var.set("")  # 密码
        Node_program.trading_sender_self_sign_text.config(state="normal")
        Node_program.trading_sender_self_sign_text.delete("1.0", "end")
        Node_program.trading_sender_self_sign_text.config(state="disabled")
        Node_program.trading_sender_self_sign_button.config(state="normal")
        # 改变签名标志
        Node_program.trading_sender_sign_flag = False

    # 连接界面的创建方法
    @staticmethod
    def connect_data_window():
        # 销毁当前容器内的组件
        Window_program.clear_frame(Node_program.normal_node_main_in_frame)
        # 设置初始变量
        Node_program.connect_data_target_var = tk.StringVar()

        # 界面提示标签
        tk.Label(Node_program.normal_node_main_in_frame, text="连接界面", font=("黑体", 15), fg="black", height=1, width=50, bd=3, padx=5, pady=5, ).grid(row=0, column=0, columnspan=3, padx=5, pady=5)

        # 已连接节点数据显示文本框
        Node_program.connect_data_show_text = tk.Text(Node_program.normal_node_main_in_frame, font=("黑体", 10), fg="black", height=30, width=80, bd=3, padx=5, pady=5, )
        Node_program.connect_data_show_text.config(state="disabled")
        Node_program.connect_data_show_text.grid(row=1, column=0, columnspan=3, padx=5, pady=5)

        # 连接指定节点的组件
        tk.Label(Node_program.normal_node_main_in_frame, text="目标序号:", font=("黑体", 15), fg="black", height=1, bd=3, padx=5, pady=5, ).grid(row=2, column=0, padx=5, pady=5)
        Node_program.connect_data_target_entry = tk.Entry(Node_program.normal_node_main_in_frame,  textvariable=Node_program.connect_data_target_var, width=20, font=("黑体", 15), fg="black", bd=3,)
        Node_program.connect_data_target_entry.grid(row=2, column=1, padx=5, pady=5)
        Node_program.connect_data_connect_button = tk.Button(Node_program.normal_node_main_in_frame,  text="连接节点", font=("黑体", 15), fg="green",  bd=3, padx=5, pady=5, command=Node_program.connect_data_connect_function)
        Node_program.connect_data_connect_button.grid(row=2, column=2, padx=5, pady=5)

        # 刷新按钮
        Node_program.connect_data_update_button = tk.Button(Node_program.normal_node_main_in_frame,  text="更新节点数据", font=("黑体", 15), fg="green",  bd=3, padx=5, pady=5, command=Node_program.connect_data_update_function_trans)
        Node_program.connect_data_update_button.grid(row=3, column=0, padx=5, pady=5)

        # 退出按钮
        Node_program.connect_data_exit_button = tk.Button(Node_program.normal_node_main_in_frame,  text="退出", font=("黑体", 15), fg="red",  bd=3, padx=5, pady=5, command=Node_program.recover_normal_node_main_in_frame)
        Node_program.connect_data_exit_button.grid(row=3, column=2, padx=5, pady=5)

        # 以线程形式展示其他节点数据的方法
        th = threading.Thread(target=Node_program.connect_data_show_data)
        th.start()

    # 显示已有数据节点的方法
    @staticmethod
    def connect_data_show_data():
        Node_program.ready_text.config(state="disabled")
        Node_program.ready_text.delete("1.0", "end")
        if Node_file_program.read_other_normal_node_data():  # 判断读取其他节点数据是否成功
            Node_program.ready_text.insert("end", "数据读取成功")
            # 清空以及显示文本框内的数据
            Node_program.connect_data_show_text.config(state='normal')
            Node_program.connect_data_show_text.delete("1.0", "end")
            Node_program.connect_data_show_text.insert("end", "")
            # 展示数据
            Node_program.connect_data_show_text.insert("end", "序号".ljust(5) + "节点名".ljust(10) + "节点ip".ljust(16) + "节点端口".ljust(5) + "节点余额".ljust(5) + "\n")
            num = len(Node_program.other_normal_node_name_list)
            for i in range(0, num):
                Node_program.connect_data_show_text.insert("end", str(i).ljust(7) + str(Node_program.other_normal_node_name_list[i]).ljust(13) + str(Node_program.other_normal_node_ip_list[i]).ljust(18) + str(Node_program.other_normal_node_port_list[i]).ljust(9) + str(Node_program.other_normal_node_balance_list[i]).ljust(9) + "\n")
            Node_program.connect_data_show_text.config(state="disabled")
        else:

            Node_program.ready_text.insert("end", "读取其他节点数据读取失败！")

    # 刷新按钮对应方法的中继方法
    @staticmethod
    def connect_data_update_function_trans():
        Node_program.connect_data_update_button.config(state="disabled")  # 刷新按钮失效
        Node_program.connect_data_exit_button.config(state="disabled")  # 退出按钮失效
        th = threading.Thread(target=Node_program.connect_data_update_function)
        th.start()

    # 刷新按钮对应的方法
    @staticmethod
    def connect_data_update_function():
        Node_program.ready_text.config(state="normal")
        Node_program.ready_text.delete("1.0", "end")
        if Node_program.sever_node_connect_flag is True:
            Node_program.sever_node_socket.send("@sever_node_change_ability".encode())
            while True:
                if Node_program.sever_node_free_flag is True:
                    break
            data = Node_program.sever_node_socket.recv(Node_program.max_data).decode()
            if data == "@normal_node_verify_tcb":
                Node_program.sever_node_socket.send("@sever_node_get_normal_node".encode())
                data = Node_program.sever_node_socket.recv(Node_program.max_data).decode()
                if data == "OK":
                    Node_program.ready_text.insert("end", "数据更新中...\n")
                    # 清空节点列表
                    Node_program.other_normal_node_name_list.clear()
                    Node_program.other_normal_node_public_key_list.clear()
                    Node_program.other_normal_node_ip_list.clear()
                    Node_program.other_normal_node_port_list.clear()
                    Node_program.other_normal_node_balance_list.clear()
                    # 接收数据
                    num = int(Node_program.sever_node_socket.recv(Node_program.max_data).decode())
                    for i in range(0, num):
                        Node_program.other_normal_node_name_list.append(Node_program.sever_node_socket.recv(Node_program.max_data).decode())
                        Node_program.other_normal_node_public_key_list.append(Node_program.sever_node_socket.recv(Node_program.max_data).decode())
                        Node_program.other_normal_node_ip_list.append(Node_program.sever_node_socket.recv(Node_program.max_data).decode())
                        Node_program.other_normal_node_port_list.append(Node_program.sever_node_socket.recv(Node_program.max_data).decode())
                        Node_program.other_normal_node_balance_list.append(Node_program.sever_node_socket.recv(Node_program.max_data).decode())
                    data = Node_program.sever_node_socket.recv(Node_program.max_data).decode()
                    if data == "OVER":
                        # 调用重写其他节点数据的方法
                        Node_file_program.update_other_normal_node_data()
                        # 调用读取其他用户节点数据的方法
                        Node_file_program.read_other_normal_node_data()
                        # 调用其他用户节点数据显示的方法
                        Node_program.connect_data_show_data()
                        Node_program.ready_text.config(state="normal")
                        Node_program.ready_text.delete("1.0", "end")
                        Node_program.ready_text.insert("end", "数据刷新完毕")
                    else:
                        Node_program.ready_text.insert("end", "数据接收存在异常！")
                else:
                    Node_program.ready_text.insert("end", "服务节点回复异常！")
            else:
                Node_program.ready_text.insert("end", "连接异常！")
            # 重启线程
            th = threading.Thread(target=Node_program.sever_node_alive_tcb, args=(Node_program.sever_node_socket, ))
            th.start()
        else:
            Node_program.ready_text.insert("end", "当前尚未连接至服务节点")
            Node_program.connect_data_update_button.config(state="normal")
        Node_program.connect_data_exit_button.config(state="normal")

    # 连接按钮对应的方法
    @staticmethod
    def connect_data_connect_function():
        Node_program.ready_text.config(state="normal")
        Node_program.ready_text.delete("1.0", "end")
        num = Node_program.connect_data_target_var.get()
        flag = False
        try:
            num = int(num)
            if num < len(Node_program.other_normal_node_name_list):
                if Node_program.other_normal_node_name_list[num] in Node_program.alive_other_node_name_list:
                    Node_program.ready_text.insert("end", "该节点已连接!")
                else:
                    flag = True
            else:
                Node_program.ready_text.insert("end", "无效序号！")
        except ValueError:
            Node_program.ready_text.insert("end", "违规输入，需为数字序号！")
        finally:
            if flag is True:
                Node_program.ready_text.insert("end", "连接中...")
                # 启用连接的线程
                th = threading.Thread(target=Node_program.connect_target_node_function, args=(Node_program.other_normal_node_name_list[num], Node_program.other_normal_node_ip_list[num], Node_program.other_normal_node_port_list[num], ))
                th.start()
            else:
                pass

    # 连接指定目标的线程方法
    @staticmethod
    def connect_target_node_function(node_name, IP, PORT):
        Node_program.ready_text.config(state="normal")
        Node_program.ready_text.delete("1.0", "end")
        connect_flag = False
        # 设置网络层协议，传输层协议
        data_socket = socket(AF_INET, SOCK_STREAM)  # IP协议，TCP
        # 由于是在同一计算机上操作的，故获取本地IP
        IP = Connection_program.get_host_ip()
        # 尝试进行连接
        try:
            data_socket.connect((IP, int(PORT)))
            data_socket.send("@normal_node_silence_connect".encode())
            data = data_socket.recv(Node_program.max_data).decode()
            if data == 'OK':  # 判断对方回复
                connect_flag = True
            else:
                data_socket.close()
        except ConnectionRefusedError:
            data_socket.close()
            Node_program.ready_text.insert("end", "连接失败！")
        finally:
            if connect_flag is True:  # 判断最终连接结果
                Node_program.alive_other_node_name_list.append(node_name)
                Node_program.alive_other_node_ip_list.append(IP)
                Node_program.alive_other_node_port_list.append(PORT)
                Node_program.alive_node_update_flag = True

    # 用户节点文件界面创建的方法
    @staticmethod
    def node_logs_file_window():
        # 销毁当前容器内的组件
        Window_program.clear_frame(Node_program.normal_node_main_in_frame)
        # 设置初始变量
        Node_program.logs_file_input_target_file_var = tk.StringVar()
        Node_program.logs_file_create_file_var = tk.StringVar()
        Node_program.logs_file_load_flag = False  # 文件是否读取成功的标志
        Node_program.logs_file_read_target_file_flag = False  # 是否读取指定文件的标志

        # 界面提示标签
        tk.Label(Node_program.normal_node_main_in_frame, text="文件操作界面", font=("黑体", 15), fg="black", height=1, width=50, bd=3, padx=5, pady=5, ).grid(row=0, column=0, columnspan=4, padx=5, pady=5)

        # 文件名显示框
        Node_program.logs_file_show_file_text = tk.Text(Node_program.normal_node_main_in_frame, font=("黑体", 10), fg="black", height=25, width=78, bd=3, padx=5, pady=5, )
        Node_program.logs_file_show_file_text.config(state="disabled")
        Node_program.logs_file_show_file_text.grid(row=1, column=0, columnspan=4, padx=5, pady=5)

        # 文件读取标签，输入栏，以及删除按钮
        tk.Label(Node_program.normal_node_main_in_frame,  text="文件序号:", font=("黑体", 15), fg="black", height=1, bd=3, padx=5, pady=5, ).grid(row=2, column=0, padx=5, pady=5)
        Node_program.logs_file_input_target_file_entry = tk.Entry(Node_program.normal_node_main_in_frame, textvariable=Node_program.logs_file_input_target_file_var, width=15, font=("黑体", 15), fg="black", bd=3, )
        Node_program.logs_file_input_target_file_entry.grid(row=2, column=1, padx=5, pady=5)
        Node_program.logs_file_read_target_file_button = tk.Button(Node_program.normal_node_main_in_frame, text="读取", font=("黑体", 15), fg="green",  bd=3, padx=5, pady=5, command=Node_program.logs_file_read_file_function)
        Node_program.logs_file_read_target_file_button.grid(row=2, column=2, padx=5, pady=5)
        Node_program.logs_file_delete_target_file_button = tk.Button(Node_program.normal_node_main_in_frame, text="删除", font=("黑体", 15), fg="red",  bd=3, padx=5, pady=5, command=Node_program.logs_file_delete_file_function)
        Node_program.logs_file_delete_target_file_button.grid(row=2, column=3, padx=5, pady=5)

        # 文件创建标签，输入栏，以及按钮
        tk.Label(Node_program.normal_node_main_in_frame,  text="创建文件:", font=("黑体", 15), fg="black", height=1, bd=3, padx=5, pady=5, ).grid(row=3, column=0, padx=5, pady=5)
        Node_program.logs_file_create_file_entry = tk.Entry(Node_program.normal_node_main_in_frame, textvariable=Node_program.logs_file_create_file_var, width=30, font=("黑体", 15), fg="black", bd=3, )
        Node_program.logs_file_create_file_entry.grid(row=3, column=1, columnspan=2, padx=5, pady=5)
        Node_program.logs_file_create_file_button = tk.Button(Node_program.normal_node_main_in_frame, text="创建", font=("黑体", 15), fg="green",  bd=3, padx=5, pady=5, command=Node_program.logs_file_create_file_function)
        Node_program.logs_file_create_file_button.grid(row=3, column=3, padx=5, pady=5)

        # 保存按钮
        tk.Button(Node_program.normal_node_main_in_frame, text="保存", font=("黑体", 15), fg="green",  bd=3, padx=5, pady=5, command=Node_program.logs_file_save_file_function).grid(row=4, column=0, padx=5, pady=5)

        # 刷新按钮
        tk.Button(Node_program.normal_node_main_in_frame, text="刷新", font=("黑体", 15), fg="green",  bd=3, padx=5, pady=5, command=Node_file_program.logs_file_read_and_show_file_data_function).grid(row=4, column=1, padx=5, pady=5)

        # 退出按钮
        tk.Button(Node_program.normal_node_main_in_frame, text="退出", font=("黑体", 15), fg="red",  bd=3, padx=5, pady=5, command=Node_program.recover_normal_node_main_in_frame).grid(row=4, column=3, padx=5, pady=5)

        # 调用读取当前文件的线程方法
        th = threading.Thread(target=Node_file_program.logs_file_read_and_show_file_data_function)
        th.start()

    # 读取文件按钮对应的方法
    @staticmethod
    def logs_file_read_file_function():
        Node_program.ready_text.config(state="normal")
        Node_program.ready_text.delete("1.0", "end")
        if Node_program.logs_file_load_flag is True:  # 判断用户节点文件是否读取成功
            # 判断序号
            target_num = Node_program.logs_file_input_target_file_var.get()
            try:
                target_num = int(target_num)
                if 0 <= target_num <= Node_program.logs_file_file_sum:
                    if Node_file_program.logs_file_read_file(Node_program.logs_file_file_list[target_num * 4]):
                        Node_program.ready_text.insert("end", "文件读取成功\n")
                        Node_program.logs_file_read_target_file_flag = True
                        Node_program.logs_file_read_target_file_name = Node_program.logs_file_file_list[target_num * 4]
                    else:
                        Node_program.ready_text.insert("end", "文件读取失败！\n")
                else:
                    Node_program.ready_text.insert("end", "无效输入！\n")
            except ValueError:
                Node_program.ready_text.insert("end", "输入序号需为数字！\n")
            finally:
                pass
        else:
            Node_program.ready_text.insert("end", "无效操作！\n")

    # 删除文件按钮对应的方法
    @staticmethod
    def logs_file_delete_file_function():
        Node_program.ready_text.config(state="normal")
        Node_program.ready_text.delete("1.0", "end")
        if Node_program.logs_file_load_flag is True:  # 判断用户节点文件是否读取成功
            # 判断序号
            target_num = Node_program.logs_file_input_target_file_var.get()
            try:
                target_num = int(target_num)
                if 0 <= target_num <= Node_program.logs_file_file_sum:
                    flag, num = Node_file_program.logs_file_delete_file(Node_program.logs_file_file_list[target_num * 4])
                    if flag is True:
                        Node_program.ready_text.insert("end", "文件删除成功\n")
                    else:
                        if num == 0:
                            Node_program.ready_text.insert("end", "不存在该文件！\n")
                        else:
                            Node_program.ready_text.insert("end", "该文件不可删除！\n")
                else:
                    Node_program.ready_text.insert("end", "无效输入！\n")
            except ValueError:
                Node_program.ready_text.insert("end", "输入序号需为数字！\n")
            finally:
                pass
        else:
            Node_program.ready_text.insert("end", "无效操作！\n")

    # 创建按钮对应的方法
    @staticmethod
    def logs_file_create_file_function():
        Node_program.ready_text.config(state="normal")
        Node_program.ready_text.delete("1.0", "end")
        if Node_program.logs_file_load_flag is True:
            # 获得创建的文件名
            file_name = Node_program.logs_file_create_file_var.get()
            if file_name == "" or file_name == ".txt":  # 判断文件名是否为空或无意义
                Node_program.ready_text.insert("end", "文件名不能为空！")
            else:
                num = len(file_name)
                if num < 4:
                    file_name = file_name + ".txt"
                else:
                    if file_name[num - 4:num] == ".txt":  # 判断该文件是否需要添加后缀
                        pass
                    else:
                        file_name += file_name + ".txt"
                # 调用文件创建的方法
                if Node_file_program.logs_file_create_file(file_name):
                    Node_program.ready_text.insert("end", "文件创建成功\n")
                else:
                    Node_program.ready_text.insert("end", "文件已存在，创建失败！\n")
        else:
            Node_program.ready_text.insert("end", "无效操作！")

    # 保存按钮对应的方法
    @staticmethod
    def logs_file_save_file_function():
        Node_program.ready_text.config(state="normal")
        Node_program.ready_text.delete("1.0", "end")
        if Node_program.logs_file_load_flag is True:
            if Node_program.logs_file_read_target_file_flag is True:
                # 判断该文件是否可以修改
                if Node_program.logs_file_read_target_file_name not in ["block_chain_data", "other_normal_node_data.txt", str(Node_program.node_name) + "_base_data.txt"]:
                    if "time_block_chain_" not in Node_program.logs_file_read_target_file_name:
                        if Node_file_program.logs_file_rewrite_file(Node_program.logs_file_read_target_file_name, Node_program.logs_file_show_file_text.get("1.0", "end")):
                            Node_program.ready_text.insert("end", "文件保存成功！\n")
                        else:
                            Node_program.ready_text.insert("end", "文件保存失败！\n")
                    else:
                        Node_program.ready_text.insert("end", "该文件不可修改！\n")
                else:
                    Node_program.ready_text.insert("end", "该文件不可修改！\n")
            else:
                Node_program.ready_text.insert("end", "您还未读取文件！\n")
        else:
            Node_program.ready_text.insert("end", "无法进行此操作！\n")

    # 由用户节点面转向节点初始界面的方法
    @staticmethod
    def normal_node_window_to_node_init_window():
        if Node_program.node_close_able_flag is True:  # 判断当前是否可以关闭节点
            Window_program.normal_node_main_frame.destroy()
            Node_program.node_work_flag = False
            Node_program.node_init_window()
        else:
            Node_program.ready_text.config(state="normal")
            Node_program.ready_text.delete("1.0", "end")
            Node_program.ready_text.insert("end", "当前节点正在处理任务，暂时无法关闭，请稍后再试！")
            Node_program.ready_text.config(state="disabled")

    # 用户节点创建界面
    @staticmethod
    def node_create_window():
        # 数据初始化设置
        Node_program.name_var = tk.StringVar()
        Node_program.ip_var = tk.StringVar()
        Node_program.port_var = tk.StringVar()
        Node_program.password1_var = tk.StringVar()
        Node_program.password2_var = tk.StringVar()

        # 初始化界面参数
        Window_program.node_create_frame = tk.Frame(root_window, relief="raised", bd=3, height=600, width=400)
        Window_program.node_create_frame.place(anchor="center", relx=0.5, rely=0.5)

        # 提示文本框
        Node_program.ready_text = tk.Text(Window_program.node_create_frame, font=("黑体", 18), fg="red", width=50, height=2, bd=3, padx=10, pady=5)
        Node_program.ready_text.insert("end", "正在尝试连接至服务节点...")
        Node_program.ready_text.config(state="disabled")
        Node_program.ready_text.grid(row=0, column=0, columnspan=4, padx=10, pady=10)

        # 节点名输入框以及提示文本
        tk.Label(Window_program.node_create_frame, text="节点名:", fg="black", font=('黑体', 15), anchor="center", padx=15, pady=10, ).grid(row=1, column=0, padx=10, pady=10)
        Node_program.name_entry = tk.Entry(Window_program.node_create_frame, width=55, fg="black", font=("黑体", 15),textvariable=Node_program.name_var)
        Node_program.name_entry.grid(row=1, column=1, columnspan=3, padx=10, pady=10)

        # 节点开启密码以及提示标签
        tk.Label(Window_program.node_create_frame, text="输入密码:", fg="black", font=('黑体', 15), anchor="center", padx=15, pady=10, ).grid(row=2, column=0, padx=10, pady=10)
        Node_program.password1_entry = tk.Entry(Window_program.node_create_frame, width=55, fg="black", font=("黑体", 15), textvariable=Node_program.password1_var)
        Node_program.password1_entry.grid(row=2, column=1, columnspan=3, padx=10, pady=10)
        # 再次输入确认以及提示标签
        tk.Label(Window_program.node_create_frame, text="确认密码:", fg="black", font=('黑体', 15), anchor="center", padx=15, pady=10, ).grid(row=3, column=0, padx=10, pady=10)
        Node_program.password2_entry = tk.Entry(Window_program.node_create_frame, width=55, fg="black", font=("黑体", 15), textvariable=Node_program.password2_var)
        Node_program.password2_entry.grid(row=3, column=1, columnspan=3, padx=10, pady=10)

        # ip输入框以及提示文本
        tk.Label(Window_program.node_create_frame, text="IP:", fg="black", font=('黑体', 15), anchor="center", padx=15, pady=10, ).grid(row=4, column=0, padx=10, pady=10)
        Node_program.ip_entry = tk.Entry(Window_program.node_create_frame, width=20, fg="black", font=("黑体", 15), textvariable=Node_program.ip_var)
        Node_program.ip_entry.grid(row=4, column=1, padx=10, pady=10)

        # 端口输入框以及提示文本
        tk.Label(Window_program.node_create_frame, text="端口:", fg="black", font=('黑体', 15), anchor="center", padx=15, pady=10, ).grid(row=4, column=2, padx=10, pady=10)
        Node_program.port_entry = tk.Entry(Window_program.node_create_frame, width=20, fg="black", font=("黑体", 15), textvariable=Node_program.port_var)
        Node_program.port_entry.grid(row=4, column=3, padx=10, pady=10)

        # 公钥显示框以及提示文本
        tk.Label(Window_program.node_create_frame, text="公钥:", fg="black", font=('黑体', 15), anchor="center", padx=15, pady=10, ).grid(row=5, column=0, padx=10, pady=10)
        Node_program.public_key_text = tk.Text(Window_program.node_create_frame,width=60, height=3, fg="black", font=("黑体", 15), padx=5, pady=5)
        Node_program.public_key_text.grid(row=5, column=1, columnspan=3, padx=10, pady=10)

        # 私钥显示框以及提示文本
        tk.Label(Window_program.node_create_frame, text="私钥:", fg="black", font=('黑体', 15), anchor="center", padx=15, pady=10, ).grid(row=6, column=0, padx=10, pady=10)
        Node_program.private_key_text = tk.Text(Window_program.node_create_frame,width=60, height=3, fg="black", font=("黑体", 15), padx=5, pady=5)
        Node_program.private_key_text.grid(row=6, column=1, columnspan=3, padx=10, pady=10)

        # 创建按钮
        Node_program.node_create_send_button = tk.Button(Window_program.node_create_frame, text="创建", fg="green", font=('黑体', 15), anchor="center", padx=15, pady=10, command=Node_program.node_create_send_function_trans)
        Node_program.node_create_send_button.config(state="disabled")
        Node_program.node_create_send_button.grid(row=7, column=0, columnspan=2, padx=10, pady=10)

        # 退出按钮
        tk.Button(Window_program.node_create_frame, text="退出", fg="red", font=('黑体', 15), anchor="center", padx=15, pady=10, command=Node_program.create_node_window_to_node_init_window).grid(row=7, column=2, columnspan=2, padx=10, pady=10)

        # 判断是否连接至服务节点
        if Node_program.node_create_connect():
            Node_program.node_create_send_button.config(state="normal")  # 改变按钮状态

    # 创建节点连接至服务几点的方法
    @staticmethod
    def node_create_connect():
        connect_flag = True  # 连接至服务节点的标志
        IP = Connection_program.get_host_ip()  # 设置目标ip
        PORT = Node_program.sever_node_port  # 设置端口号
        # 设置网络层协议，传输层协议
        data_socket = socket(AF_INET, SOCK_STREAM)  # IP协议，TCP
        # 尝试进行连接
        try:
            data_socket.connect((IP, PORT))
        except ConnectionRefusedError:
            data_socket.close()
            connect_flag = False
        finally:
            Node_program.ready_text.config(state="normal")
            Node_program.ready_text.delete("1.0", "end")
            if connect_flag is True:
                data_socket.send("@sever_node_node_create".encode())
                data = data_socket.recv(Node_program.max_data).decode()
                if data == "OK":
                    Node_program.ready_text.insert("end", "已连接至服务节点\n请填入创建数据，公私钥将自动生成")
                    Node_program.ready_text.config(state="disabled")
                    Node_program.node_create_connect_flag = True
                    Node_program.node_create_socket = data_socket
                    return True
                else:
                    Node_program.ready_text.insert("end", "请求失败！")
                    data_socket.close()
            else:
                Node_program.ready_text.insert("end", "无法连接至服务节点！")
                Node_program.ready_text.config(state="disabled")
                return False

    # 创建按钮的中继方法
    @staticmethod
    def node_create_send_function_trans():
        th = threading.Thread(target=Node_program.node_create_send_function)
        th.start()

    # 节点创建按钮对应的方法
    @staticmethod
    def node_create_send_function():
        pass_flag = True
        # 改变组件状态
        Node_program.node_create_send_button.config(state="disabled")
        Node_program.node_create_try_flag = True
        # 获得输入的数据
        name = Node_program.name_var.get()
        ip = Node_program.ip_var.get()
        port = Node_program.port_var.get()
        password1 = Node_program.password1_var.get()
        password2 = Node_program.password2_var.get()
        # 检测输入的数据
        # 节点名检测
        if name == "" or name == "节点名不可为空！" or name == "AWARD":
            pass_flag = False
            Node_program.name_var.set("节点名不可为空！")
        pass_flag = False
        if password1 != "" and password1 != "密码不能为空！":
            if Crypto_program.test_key_strong(password1, 16):
                if password1 == password2:
                    pass_flag = True
                else:
                    Node_program.password2_var.set("密钥不一致！")
            else:
                Node_program.password1_var.set("强度不够或不合法，须至少同时含有字母与数字")
        else:
            Node_program.password1_var.set("密码不能为空！")

        # ip检测
        match_result = re.match(r'((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}', ip)
        if ip == "" or ip == "ip不可为空！":
            pass_flag = False
            Node_program.ip_var.set("ip不可为空！")
        elif match_result is None or ip == "形如：xxx.xxx.xxx.xxx":
            pass_flag = False
            Node_program.ip_var.set("形如：xxx.xxx.xxx.xxx")
        # 端口号检测
        try:
            num = int(port)
            if num < 0 or num > 65553:
                pass_flag = False
                Node_program.port_var.set("应在 0-65553 之间")
        except ValueError:
            pass_flag = False
            Node_program.port_var.set("格式错误，应为数字！")
        finally:
            pass
        # 判断检测结果
        if pass_flag is True:
            Node_program.ready_text.config(state="normal")
            Node_program.ready_text.delete("1.0", "end")
            Node_program.ready_text.insert("end", "正在发送节点数据中...")
            # 调用生成并获得公私钥的方法
            Crypto_program.sm2_all_key_born()
            while True:
                if Crypto_program.self_sm2_public_key != "" and Crypto_program.self_sm2_private_key != "":
                    break
            Node_program.node_public_key = Crypto_program.self_sm2_public_key
            Node_program.node_private_key = Crypto_program.self_sm2_private_key
            Node_program.public_key_text.insert("end", Node_program.node_public_key)
            Node_program.private_key_text.insert("end", Node_program.node_private_key)
            # 依次发送消息
            time.sleep(1)
            Node_program.node_create_socket.send(str(name).encode())  # 节点名
            time.sleep(1)
            Node_program.node_create_socket.send(str(Node_program.node_public_key).encode())  # 公钥
            time.sleep(1)
            Node_program.node_create_socket.send(str(ip).encode())  # ip
            time.sleep(1)
            Node_program.node_create_socket.send(str(port).encode())  # 端口
            time.sleep(1)
            Node_program.ready_text.delete("1.0", "end")
            Node_program.ready_text.insert("end", "节点数据发送完毕，正在等待验证...")
            data = Node_program.node_create_socket.recv(Node_program.max_data).decode()  # 接收服务节点处理结果
            if data == "OK":
                Node_program.ready_text.delete("1.0", "end")
                Node_program.ready_text.insert("end", "创建的节点数据通过\n")
                data = Node_program.node_create_socket.recv(Node_program.max_data).decode()  # 接收服务节点保存结果
                if data == "OK":
                    Node_program.ready_text.delete("1.0", "end")
                    Node_program.ready_text.insert("end", "服务节点已收录您的节点数据")
                    data = Node_program.node_create_socket.recv(Node_program.max_data).decode()  # 接收下一步操作
                    Node_program.ready_text.delete("1.0", "end")
                    if data == "OK":
                        Node_program.ready_text.insert("end", "正在接收区块链数据...")
                        # 接收当前区块链数量
                        blockchain_length = Node_program.node_create_socket.recv(Node_program.max_data).decode()
                        blockchain_data_list = []
                        # 依次接受每个区块链数据
                        for _ in range(0, int(blockchain_length)):
                            # 接收区块头
                            version = Node_program.node_create_socket.recv(Node_program.max_data).decode()  # 版本号
                            blockchain_data_list.append(version)
                            pre_hash = Node_program.node_create_socket.recv(Node_program.max_data).decode()  # 前一个区块的哈希值
                            blockchain_data_list.append(pre_hash)
                            timestamp = Node_program.node_create_socket.recv(Node_program.max_data).decode()  # 时间戳
                            blockchain_data_list.append(timestamp)
                            meckel = Node_program.node_create_socket.recv(Node_program.max_data).decode()  # 梅克尔根
                            blockchain_data_list.append(meckel)
                            diff = Node_program.node_create_socket.recv(Node_program.max_data).decode()  # 难度
                            blockchain_data_list.append(diff)
                            random_num = Node_program.node_create_socket.recv(Node_program.max_data).decode()  # 随机数
                            blockchain_data_list.append(random_num)
                            index = Node_program.node_create_socket.recv(Node_program.max_data).decode()  # 序列号
                            blockchain_data_list.append(index)
                            # 接收区块体
                            # 接收交易数量
                            num = Node_program.node_create_socket.recv(Node_program.max_data).decode()  # 交易数量
                            blockchain_data_list.append(num)
                            # 接收具体交易数据
                            for _ in range(0, int(num)):
                                sender = Node_program.node_create_socket.recv(Node_program.max_data).decode()  # 付款方
                                blockchain_data_list.append(sender)
                                receiver = Node_program.node_create_socket.recv(Node_program.max_data).decode()  # 收款方
                                blockchain_data_list.append(receiver)
                                amount = Node_program.node_create_socket.recv(Node_program.max_data).decode()  # 数额
                                blockchain_data_list.append(amount)
                        data = Node_program.node_create_socket.recv(Node_program.max_data).decode()  # 结束验证消息
                        # 调用相关方法保存创建的用户节点数据
                        Node_program.ready_text.delete("1.0", "end")
                        if data == "OVER":
                            if Node_file_program.create_node_folder_and_file(name, password1, Node_program.node_public_key, Node_program.node_private_key, ip, port, blockchain_length, blockchain_data_list):
                                Node_program.ready_text.insert("end", "节点数据已保存")
                            else:
                                Node_program.ready_text.insert("end", "节点数据保存失败！")
                        else:
                            Node_program.ready_text.insert("end", "区块链数据接收异常！")
                    else:
                        Node_program.ready_text.insert("end", "当前暂时无法获得区块链数据！")
                    Node_program.node_create_socket.close()
                    Node_program.node_create_connect_flag = False
                else:
                    Node_program.ready_text.insert("end", "服务节点收录异常！")
            elif data == "FALSE_NAME":
                Node_program.ready_text.delete("1.0", "end")
                Node_program.ready_text.insert("end", "节点名重复！")
            elif data == "FALSE_KEY":
                Node_program.ready_text.delete("1.0", "end")
                Node_program.ready_text.insert("end", "公钥不符合！")
            elif data == "FALSE_PORT":
                Node_program.ready_text.delete("1.0", "end")
                Node_program.ready_text.insert("end", "端口不符合！")
            else:
                Node_program.ready_text.delete("1.0", "end")
                Node_program.ready_text.insert("end", "创建的节点数据未通过！")
        else:
            Node_program.node_create_send_button.config(state="normal")

    # 节点创建界面返回节点初始界面的方法
    @staticmethod
    def create_node_window_to_node_init_window():
        if Node_program.node_create_connect_flag is True:
            if Node_program.node_create_try_flag is True:
                Node_program.node_create_socket.send("@sever_node_node_create_exit".encode())
                Node_program.node_create_try_flag = False
            else:
                # 节点取消注册，发送对应指令
                Node_program.node_create_socket.send("@sever_node_node_create_exit".encode())
            Node_program.node_create_connect_flag = False
        Window_program.node_create_frame.destroy()
        Node_program.node_init_window()


# 处理区块链数据密码学相关的类
class Block_program(object):
    def __init__(self):
        super().__init__()

    # 区块链版本号
    version = "20231212"
    # 区块链难度
    diff = "2"
    min_work_success_num = 10  # 每次挖矿成功最小的奖励数额
    # 数据验证变量

    # 初始处理数据的方法
    """
    用于将数据整理成符合区块链数据格式的方法
    需要加入用户节点名，获取时间戳
    """
    @staticmethod
    def init_block_data(index):
        """
        :param index: 区块序列
        :return: head_data， body_data:区块头字典，区块体列表
        """
        # 初始化区块体数据
        body_data = ["1", "1", "AWARD", str(Node_program.node_name), str(Block_program.min_work_success_num)]
        # 获得区块体的哈希值
        body_data_hash = sm3.sm3_hash(func.bytes_to_list(("11AWARD" + str(Node_program.node_name) + str(Block_program.min_work_success_num)).encode()))
        # 获取当前的时间戳
        timestamp = time.time()
        # 组合区块头
        head_data = {
            "version": Block_program.version,  # 具体意义为创世区块创建的年月日
            "pre_hash": str(Node_file_program.now_block_head_hash),
            "timestamp": str(timestamp),  # 为简化过程,检测时，同一天内即可
            "Merk": body_data_hash,
            "diff": str(Block_program.diff),
            "random_num": "",  # 限制长度为 4 字节,不足用0补充
            "index": str(index + 1),  # 区块序列，表明该区块是第几个产生的
        }
        return head_data, body_data

    # 挖矿的方法  (1.00)
    @staticmethod
    def block_mine():
        """
        该版本的挖矿方法实质为 000-999 之间的字符串测试，当到测试到目标值时会跳出循环，反之若未寻找到，则会提示限定条件内未找到目标值
        :return: None
        """
        index = int(Node_program.node_blockchain_length) - 1  # 将当前区块链数减一以获得当前区块链的序列号
        if Node_file_program.read_target_block_data(Node_program.node_name, index):  # 调用并读取节点指定文件
            # 初始化即将挖取的区块数据
            data, body_data = Block_program.init_block_data(index)
            diff = Block_program.diff
            # 改变组件参数
            Node_program.mine_work_show_detail_text.config(state="normal")
            Node_program.mine_work_target_hast_text.config(state="normal")
            Node_program.mine_work_target_random_num_text.config(state="normal")
            # 进行挖矿准备
            item = data["version"] + data["pre_hash"] + data["timestamp"] + data["Merk"] + data["diff"]
            target = ""
            # 开始挖矿
            Node_program.ready_text.config(state="normal")
            Node_program.ready_text.delete("1.0", "end")
            Node_program.ready_text.insert("end", "挖矿中...")
            for _ in range(0, int(diff)):
                target += "0"
            if str(diff) == data["diff"]:
                random_num = 0
                while True:
                    if Node_program.mine_work_stop_flag is True:  # 判断是否暂停当前挖矿
                        while True:
                            if Node_program.mine_work_stop_flag is False:  # 判断是否恢复当前挖矿
                                break
                    if Node_program.mine_work_exit_flag is True:  # 判断是否退出当前挖矿
                        break
                    fill = 4 - len(str(random_num))
                    fill_num = str(random_num)
                    for _ in range(0, fill):
                        fill_num = "0" + fill_num
                    hash_data = sm3.sm3_hash(func.bytes_to_list((str(item) + str(fill_num)).encode()))
                    random_num += 1
                    Node_program.mine_work_show_detail_text.insert("end", hash_data + "\n")
                    if hash_data[:int(diff)] == target:
                        Node_program.ready_text.config(state="normal")
                        Node_program.ready_text.delete("1.0", "end")
                        Node_program.ready_text.insert("end", "挖矿成功！")
                        Node_program.mine_work_target_hast_text.insert("end", hash_data)
                        Node_program.mine_work_target_random_num_text.insert("end", fill_num)
                        # 保存区块数据
                        data["random_num"] = str(fill_num)  # 加入随机数值
                        Node_program.mine_work_head_dict = data  # 保存区块头字典
                        Node_program.mine_work_body_list = body_data  # 保存区块体列表
                        if Node_file_program.time_block_chain_data_file_born(Node_program.mine_work_head_dict, Node_program.mine_work_body_list):
                            Node_program.ready_text.insert("end", "\n结果已保存为临时文件")
                        else:
                            Node_program.ready_text.insert("end", "\n结果保存失败！")

                        break
                    elif random_num > 9999:
                        Node_program.ready_text.config(state="normal")
                        Node_program.ready_text.delete("1.0", "end")
                        Node_program.ready_text.insert("end", "挖矿失败...(0000-9999内未找到符合数)")
                        break
                    else:
                        random_num += 1
                Node_program.mine_work_flag = False  # 改变挖矿状态
                Node_program.mine_work_exit_button.config(state="normal")  # 改变挖矿退出按钮状态
            else:
                Node_program.ready_text.config(state="normal")
                Node_program.ready_text.delete("1.0", "end")
                Node_program.ready_text.insert("end", "数据异常！")
        else:
            pass

    # 验证节点发来的交易验证的方法   接收数据类型： 字典  返回验证结果
    @staticmethod
    def verify_node_trading_data(data_dict, mode):  # 变量类型为： 字典，交易类型标志
        """
        :param data_dict: 交易数据的字典
        :param mode: 交易类型
        :return: True or False
        """
        global payer_sign, payee_sign
        if Node_file_program.read_other_normal_node_data():
            flag = False
            # 获得交易数据
            payer = data_dict["payer"]  # 付款节点
            payee = data_dict["payee"]  # 收款节点
            amount = data_dict["amount"]  # 金额
            timestamp = data_dict["timestamp"]  # 时间戳
            if mode == "1":
                payer_sign = data_dict["sign"]  # 付款方签名
            else:
                payer_sign = data_dict["payer_sign"]  # 付款方签名
                payee_sign = data_dict["payee_sign"]  # 收款方签名
            # print(payer, payee, amount, timestamp, sign)  # 数据检测点
            try:
                # 判断时间
                now_time = time.time()
                trading_time = int(timestamp)
                if now_time - trading_time <= 3600:
                    # 验证付款方签名
                    counter = 0
                    for item in Node_program.other_normal_node_name_list:
                        if payer == item:
                            break
                        else:
                            counter += 1
                    sm2_crypto = sm2.CryptSM2("", Node_program.other_normal_node_public_key_list[counter])
                    if sm2_crypto.verify(payer_sign, sm3.sm3_hash(func.bytes_to_list(("1" + payer + payee + timestamp).encode()))):
                        if mode == "1":
                            # 验证余额
                            if Node_file_program.normal_node_wealth_record(payer, amount, "0") and Node_file_program.normal_node_wealth_record(payee, amount, "1"):  # 调用用户节点余额处理的方法
                                flag = True
                            else:
                                flag = False
                        else:
                            # 验证收款方签名
                            counter = 0
                            for item in Node_program.other_normal_node_name_list:
                                if payee == item:
                                    break
                                else:
                                    counter += 1
                            sm2_crypto = sm2.CryptSM2("", Node_program.other_normal_node_public_key_list[counter])
                            if sm2_crypto.verify(payee_sign, sm3.sm3_hash(func.bytes_to_list(("1" + payer + payee + timestamp).encode()))):
                                # 验证余额
                                if Node_file_program.normal_node_wealth_record(payer, amount, "0") and Node_file_program.normal_node_wealth_record(payee, amount, "1"):  # 调用用户节点余额处理的方法
                                    flag = True
                                else:
                                    flag = False
                    else:
                        flag = False
                else:
                    flag = False
            except ValueError:
                flag = False
            finally:
                # 返回最终判断结果
                return flag
        else:
            return False

    # 验证节点发来的区块链数据验证的方法   接收数据类型： 字典  返回验证结果
    @staticmethod
    def verify_node_block_chain_data(head_dict, body_list):
        """
        输入数据类型： 区块头字典， 区块体列表
        其中区块头数据格式：版本号，前一个区块的哈希值，梅克尔根，时间戳，难度，序列
        区块体列表列表数据格式：交易数量，交易类型：1 付款方，收款方，时间戳，付款方签名
                                           2 付款方，收款方，时间戳，付款方签名，收款方签名
        验证通过后会自动将该区块更新到区块文件中
        :param head_dict:
        :param body_list:
        :return: True or False
        """
        Node_program.ready_text.config(state="normal")
        Node_program.ready_text.delete("1.0", "end")
        verify_flag = False
        try:
            if int(Node_program.node_blockchain_length) + 1 == int(head_dict["index"]):  # 判断该区块的序列
                hash_flag, meckel = Block_program.calculate_meckel(body_list)
                if hash_flag is True and meckel == str(head_dict["meckel"]):  # 判断梅克尔根计算结果以及值的比较
                    if float(time.time()) - float(head_dict["timestamp"]) <= 3600:  # 判断时间戳是否合规
                        hash_data = sm3.sm3_hash(func.bytes_to_list(str(head_dict["version"]) + str(head_dict["pre_hash"]) + str(head_dict["meckel"]) + str(head_dict["diff"]) + str(head_dict["random_num"])))
                        diff_num = 0
                        for i in hash_data:
                            if i == "0":
                                diff_num += 1
                        if int(diff_num) >= int(Block_program.diff):
                            verify_flag = True
                            # 调用区块文件更新的方法
                            if Node_file_program.update_block_chain_data(head_dict, body_list):
                                Node_program.ready_text.insert("end", "区块文件已更新\n")
                            else:
                                Node_program.ready_text.insert("end", "区块文件更新失败！\n")
        except ValueError:
            Node_program.ready_text.insert("end", "区块数据验证异常！")
        finally:
            return verify_flag

    # 计算梅克尔根的方法
    @staticmethod
    def calculate_meckel(body_list):
        """
        输入的数据类型为列表，其数据的格式及意义为：区块体的交易列表，首行为交易数量
        :param body_list:
        :return: True, 梅克尔根 or False, None
        """
        flag = False
        trading_hash_list = []  # 用于记录历次交易的哈希值
        meckel_data = ""  # 最终的梅克尔根
        try:
            trading_num = int(body_list[0])  # 获得交易数量
            body_list.remove(body_list[0])
            trading_counter = 0
            data_counter = 0
            # 计算每个具体交易的哈希值
            while True:
                if str(body_list[data_counter]) == "1":  # 判断交易类型
                    trading_hash_list.append(sm3.sm3_hash(func.bytes_to_list((str(body_list[data_counter]) + str(
                        body_list[data_counter + 1]) + str(body_list[data_counter + 2]) + str(
                        body_list[data_counter + 3]) + str(body_list[data_counter + 4]) + str(
                        body_list[data_counter + 5])).encode())))
                    data_counter += 6
                else:
                    trading_hash_list.append(sm3.sm3_hash(func.bytes_to_list((str(body_list[data_counter]) + str(
                        body_list[data_counter + 1]) + str(body_list[data_counter + 2]) + str(
                        body_list[data_counter + 3]) + str(body_list[data_counter + 4]) + str(
                        body_list[data_counter + 5]) + str(body_list[data_counter + 6])).encode())))
                    data_counter += 7
                trading_counter += 1
                if trading_counter == trading_num:  # 判断已计算的交易数量
                    break
            # 计算梅克尔根
            hash_data_num = int(len(trading_hash_list))
            time_list = []
            while True:
                if hash_data_num == 1:  # 判断数据是否计算到了最后一个
                    meckel_data = trading_hash_list[0]
                    flag = True
                    break
                if hash_data_num % 2 == 0:  # 判断数据个数的奇偶性
                    for i in range(0, hash_data_num, 2):
                        time_list.append(sm3.sm3_hash(func.bytes_to_list((str(trading_hash_list[i]) + str(trading_hash_list[i + 1])).encode())))
                else:
                    hash_data_num -= 1
                    for i in range(0, hash_data_num, 2):
                        time_list.append(sm3.sm3_hash(func.bytes_to_list((str(trading_hash_list[i]) + str(trading_hash_list[i + 1])).encode())))
                    time_list.append(trading_hash_list[hash_data_num])
                # 重置数据，为下一次计算作准备
                trading_hash_list.clear()
                trading_hash_list.extend(time_list)
                time_list.clear()
                hash_data_num = int(len(trading_hash_list))
        except ValueError:
            flag = False
        finally:
            if flag is True:
                return True, meckel_data
            else:
                return flag, None


# 节点独有的文件处理类
class Node_file_program(object):
    def __init__(self):
        super().__init__()

    file_folder_path = "E:\python练习\pythonProject\pyp2p_practice\\"  # 节点文件夹的绝对路径
    normal_node_folder = ""  # 用户文件夹
    block_chain_folder = ""  # 用户区块链数据文件夹
    block_chain_data_list = []  # 显示区块链数据的列表
    now_block_head_hash = ""  # 当前区块头的哈希值

    # 内存模拟算法
    memory_simulate_max_distribution = 5000  # 默认最大内存分配
    memory_simulate_start_address = 20000  # 默认分配起始地址
    memory_simulate_single_block = 200  # 默认单个块大小
    memory_simulate_free_area = 0  # 空闲大小
    memory_simulate_distribute_flag = False  # 模拟分配成功的标志

    # 创建指定用户文件夹以及相关文件的方法
    @staticmethod
    def create_node_folder_and_file(name, password, public_key, private_key, ip, port, blockchain_length, blockchain_data_list):
        """
        在该方法中，创建了用户文件夹，在该文件夹下，又创建了区块链数据文件夹，用户节点数据文件，其他节点数据文件
        :param name:节点名
        :param password:节点密码
        :param public_key:节点公钥
        :param private_key:节点私钥
        :param ip:节点ip地址
        :param port:节点端口
        :param blockchain_length:节点区块链长度
        :param blockchain_data_list:节点区块链数据
        :return:True or False:创建结果
        """
        if os.path.exists(Node_file_program.file_folder_path + "normal(4.00)_node_" + name + "_folder"):  # 检测文件夹是否存在
            return False
        else:
            os.mkdir(Node_file_program.file_folder_path + "normal(4.00)_node_" + name + "_folder")  # 创建文件夹
            Node_file_program.normal_node_folder = Node_file_program.file_folder_path + "normal(4.00)_node_" + name + "_folder\\"

            # 创建用户节点自身基础数据文件
            file = open((Node_file_program.normal_node_folder + name + "_base_data.txt"), "a")
            # 写入节点名
            file.write(pysm4.encrypt_ecb(name, password) + "\n")
            file.write("@file_should_division\n")
            # 写入节点开启密码
            file.write(pysm4.encrypt_ecb(password, password) + "\n")
            file.write("@file_should_division\n")
            # 写入节点公钥
            file.write(pysm4.encrypt_ecb(public_key, password) + "\n")
            file.write("@file_should_division\n")
            # 写入节点私钥
            file.write(pysm4.encrypt_ecb(private_key, password) + "\n")
            file.write("@file_should_division\n")
            # 写入节点Ip
            file.write(pysm4.encrypt_ecb(ip, password) + "\n")
            file.write("@file_should_division\n")
            # 写入节点port
            file.write(pysm4.encrypt_ecb(port, password) + "\n")
            file.write("@file_should_division\n")
            # 写入当前区块链长度
            file.write(pysm4.encrypt_ecb(blockchain_length, password) + "\n")
            file.write("@file_should_division\n")
            # 写入节点余额
            file.write(pysm4.encrypt_ecb("0", password) + "\n")
            file.write("@file_should_division\n")
            file.close()

            # 创建用户几点已知节点数据文件
            file = open(Node_file_program.normal_node_folder + "other_normal_code_data.txt", "a")
            file.close()

            # 创建用户节点区块链文件夹
            os.mkdir(Node_file_program.normal_node_folder + "block_chain_data")
            Node_file_program.block_chain_folder = Node_file_program.normal_node_folder + "block_chain_data\\"
            counter = 0
            for i in range(0, int(blockchain_length)):  # 按照区块的数量创建文件
                file = open((Node_file_program.block_chain_folder + "block_chain_" + str(i) + ".txt"), "a")
                # 区块头
                # 标志符
                file.write("@HEAD\n")
                # 版本号
                file.write(blockchain_data_list[counter] + "\n")
                counter += 1
                # 前一个区块的哈希值
                file.write(blockchain_data_list[counter] + "\n")
                counter += 1
                # 时间戳
                file.write(blockchain_data_list[counter] + "\n")
                counter += 1
                # 梅克尔根
                file.write(blockchain_data_list[counter] + "\n")
                counter += 1
                # 难度
                file.write(blockchain_data_list[counter] + "\n")
                counter += 1
                # 随机数
                file.write(blockchain_data_list[counter] + "\n")
                counter += 1
                # 序列号
                file.write(blockchain_data_list[counter] + "\n")
                counter += 1
                # 区块体
                # 标志符
                file.write("@BODY\n")
                # 交易数量
                file.write(blockchain_data_list[counter] + "\n")
                num = blockchain_data_list[counter]
                counter += 1
                for _ in range(0, int(num)):  # 按照交易数量写入数据
                    # 付款方
                    file.write(blockchain_data_list[counter] + "\n")
                    counter += 1
                    # 收款方
                    file.write(blockchain_data_list[counter] + "\n")
                    counter += 1
                    # 数额
                    file.write(blockchain_data_list[counter] + "\n")
                    counter += 1
                file.close()
            return True

    # 节点原始加密数据读取的方法
    @staticmethod
    def normal_node_init_read(name):
        flag = True
        try:
            file = open(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(name) + "_folder\\" + str(name) + "_base_data.txt", "r")
            counter = 0
            time_data = ""
            for item in file.readlines():
                if item == "@file_should_division\n":
                    if counter == 0:
                        Node_program.node_name = time_data.rstrip("\n")
                    elif counter == 1:
                        Node_program.node_password = time_data.rstrip("\n")
                    elif counter == 2:
                        Node_program.node_public_key = time_data.rstrip("\n")
                    elif counter == 3:
                        Node_program.node_private_key = time_data.rstrip("\n")
                    elif counter == 4:
                        Node_program.node_ip = time_data.rstrip("\n")
                    elif counter == 5:
                        Node_program.node_port = time_data.rstrip("\n")
                    elif counter == 6:
                        Node_program.node_blockchain_length = time_data.rstrip("\n")
                    else:
                        Node_program.node_balance = time_data.rstrip("\n")
                    time_data = ""
                    counter += 1
                else:
                    time_data += item
                file.close()
        except IOError:  # 接收文件读取错误
            flag = False
        finally:
            return flag

    # 读取当前用户节点区块链数据以及显示的方法
    @staticmethod
    def block_chain_data_read_and_show(name):
        Node_program.ready_text.config(state="normal")
        Node_program.ready_text.delete("1.0", "end")
        Node_program.normal_node_block_chain_data_text.delete("1.0", "end")
        # 检测区块链文件是否缺失
        if os.path.exists(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(name) + r"_folder\block_chain_data"):
            flag = True
            # 清空当前区块链列表中的数据
            Node_file_program.block_chain_data_list.clear()
            # 开始读取数据
            num = len(os.listdir(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(name) + r"_folder\block_chain_data"))  # 获得区块链文件的个数
            for i in range(0, num):
               Node_file_program.block_chain_data_list.append(" =========================== 第 {} 块区块链数据 =========================== \n".format(i))
               try:
                   file = open(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(name) + r"_folder\block_chain_data\block_chain_" + str(i) + ".txt")
                   Node_file_program.block_chain_data_list.extend(file.readlines())
                   file.close()
               except IOError:
                   Node_program.ready_text.insert("end", "区块链文件序号: {} 读取异常！".format(i))
                   flag = False
               finally:
                   # 展示读取到的区块链数据
                   Node_program.normal_node_block_chain_data_text.config(state="normal")
                   for data in Node_file_program.block_chain_data_list:
                       Node_program.normal_node_block_chain_data_text.insert("end", data)
                   Node_program.normal_node_block_chain_data_text.insert("end", "====================== 当前节点区块链数据显示完毕! ======================")
                   Node_program.normal_node_block_chain_data_text.config(state="disabled")
            if flag is True:
                Node_program.ready_text.insert("end", "区块链数据全部读取完毕!")
            else:
                Node_program.ready_text.insert("end", "区块链数据部分读取异常！")
        else:
            Node_program.ready_text.insert("end", "区块链文件数据读取异常！")

    # 读取指定区块链数据文件的方法
    @staticmethod
    def read_target_block_data(name, index):  # index 为区块链文件的序号
        Node_program.ready_text.config(state="normal")
        Node_program.ready_text.delete("1.0", "end")
        if os.path.exists(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(name) + r"_folder\block_chain_data\block_chain_" + str(index) + ".txt"):
            flag = True
            file = open(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(name) + r"_folder\block_chain_data\block_chain_" + str(index) + ".txt", "r")
            content_list = file.readlines()
            version = content_list[1].rstrip("\n")
            pre_hash = content_list[2].rstrip("\n")
            timestamp = content_list[3].rstrip("\n")
            meckel = content_list[4].rstrip("\n")
            diff = content_list[5].rstrip("\n")
            random_num = content_list[6].rstrip("\n")
            hash_data = sm3.sm3_hash(func.bytes_to_list((version+pre_hash+timestamp+meckel+diff+random_num).encode()))
            zero_diff = ""
            # 验证该区块是否合规
            try:
                for _ in range(0, int(diff)):
                    zero_diff += "0"
                if hash_data[0:int(diff)] == zero_diff:
                    Node_file_program.now_block_head_hash = hash_data
                else:
                    flag = False
                    Node_program.ready_text.insert("end", "区块链文件 {} 数据存在问题！".format(index))
            except ValueError:
                Node_program.ready_text.insert("end", "区块链文件 {} 异常！".format(index))
                flag = False
            finally:
                return flag
        else:
            Node_program.ready_text.insert("end", "区块链数据文件丢失！")
            return False

    # 基于挖矿成功的结果生成临时区块链数据文件的方法
    @staticmethod
    def time_block_chain_data_file_born(head_dict, body_list):  # 传入的区块头需为字典类型, 区块体为列表类型
        """
        :param head_dict: 区块头字典
        :param body_list: 区块体列表
        :return: True or False
        """
        # 校验数据
        if head_dict != "" and body_list != "" and head_dict["index"] != "" and type(head_dict) == dict and type(body_list) == list:
            if os.path.exists(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(Node_program.node_name) + "_folder"):
                file = open(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(Node_program.node_name) + r"_folder\time_block_chain_" + str(head_dict["index"]) + ".txt", "w")
                file.write("@HEAD\n")
                for item in head_dict:
                    file.write(head_dict[item] + "\n")
                file.write("@BODY\n")
                for item in body_list:
                    file.write(item + "\n")
                file.close()
                return True
            else:
                return False
        else:
            return False

    # 更新当前区块链数据文件的方法
    @staticmethod
    def update_block_chain_data(head_dict, body_list):
        """
        head_dict: 区块头
        body_list: 区块体
        功能：为单个区块数据创建对应的文件，
            同时更新当前节点数据文件
            返回失败则说明该区块数据文件已存在
        :param head_dict:区块头字典
        :param body_list:区块体列表
        :return: True or False
        """
        if os.path.exists(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(Node_program.node_name) + "_folder"):  # 检测文件夹是否存在
            Node_program.ready_text.config(state="normal")
            Node_program.ready_text.delete("1.0", "end")
            create_flag = False
            try:
                if os.path.exists(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(Node_program.node_name) + r"_folder\block_chain_" + str(head_dict["index"]) + ".txt"):  # 判断该区块文件是否已存在
                    pass
                else:
                    file = open(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(Node_program.node_name) + r"_folder\block_chain_" + str(head_dict["index"]) + ".txt", "a")
                    file.write("@HEAD\n")
                    file.write(head_dict["version"] + "\n")
                    file.write(head_dict["pre_hash"] + "\n")
                    file.write(head_dict["meckel"] + "\n")
                    file.write(head_dict["timestamp"] + "\n")
                    file.write(head_dict["diff"] + "\n")
                    file.write(head_dict["index"] + "\n")
                    file.write("@BODY\n")
                    for item in body_list:
                        file.write(item + "\n")
                    create_flag = True
            except IOError:
                Node_program.ready_text.insert("end", "区块文件创建异常！\n")
            finally:
                return create_flag

    # 节点余额处理的方法  返回处理结果
    @staticmethod
    def normal_node_wealth_record(name, amount, mode):  # 数据依次为：操作节点名，操作金额， 操作模式(1 加， 0 减)
        """
        描述；用于操作节点的余额更改的方法，同时会判断节点是否存在，以及节点余额是否足够，
        :param name: 目标节点名
        :param amount: 金额数目
        :param mode: 操作模式(1 加，0 减)
        :return: True or False
        """
        if os.path.exists(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(Node_program.node_name) + "_folder\other_normal_node_data.txt") and Node_file_program.read_other_normal_node_data:  # 判断目标文件是否存在
            # 修改列表
            flag = False
            num = len(Node_program.other_normal_node_balance_list)
            for i in range(0, num):
                if Node_program.other_normal_node_name_list[i] == name:  # 判断节点名
                    try:
                        if str(mode) == "1":  # 判断操作模式
                            Node_program.other_normal_node_balance_list[i] = str(int(Node_program.other_normal_node_balance_list[i]) + int(amount))
                            flag = True
                        else:
                            if (int(Node_program.other_normal_node_balance_list[i]) - int(amount)) >= 0:  # 判断节点余额
                                Node_program.other_normal_node_balance_list[i] = str(int(Node_program.other_normal_node_balance_list[i]) - int(amount))
                                flag = True
                            else:
                                flag = False
                    except ValueError:
                        flag = False
                    finally:
                        pass
            # 判断收款节点是否为当前节点
            if mode == "1":
                if name == str(Node_program.node_name):
                    Node_program.node_balance = str(int(amount) + int(Node_program.node_balance))
                    # 调用重写节点数据的方法
                    if Node_file_program.update_self_node_data():
                        flag = True
            if flag is True:  # 判断操作结果
                # 重写文件
                file = open(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(Node_program.node_name) + "_folder\other_normal_node_data.txt", "w")
                for i in range(0, num):
                    file.write(Node_program.other_normal_node_name_list[i] + "\n")
                    file.write(Node_program.other_normal_node_public_key_list[i] + "\n")
                    file.write(Node_program.other_normal_node_ip_list[i] + "\n")
                    file.write(Node_program.other_normal_node_port_list[i] + "\n")
                    file.write(Node_program.other_normal_node_balance_list[i] + "\n")
                file.close()
                return True
            else:
                return False
        else:
            return False

    # 更新用户节点当前数据文件的方法
    """
        先更新当前用户节点的数据列表，再根据列表数据更新文件数据
    """
    @staticmethod
    def update_self_node_data():
        if os.path.exists(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(Node_program.node_name) + "_folder"):  # 检测文件夹是否存在
            if os.path.exists(Node_file_program.normal_node_folder + str(Node_program.node_name) + "_base_data.txt"):
                password = str(Node_program.node_password)
                # 重写用户节点自身基础数据文件
                file = open((Node_file_program.normal_node_folder + str(Node_program.node_name) + "_base_data.txt"), "w")
                # 写入节点名
                file.write(pysm4.encrypt_ecb(str(Node_program.node_name), password) + "\n")
                file.write("@file_should_division\n")
                # 写入节点开启密码
                file.write(pysm4.encrypt_ecb(str(Node_program.node_password), password) + "\n")
                file.write("@file_should_division\n")
                # 写入节点公钥
                file.write(pysm4.encrypt_ecb(str(Node_program.node_public_key), password) + "\n")
                file.write("@file_should_division\n")
                # 写入节点私钥
                file.write(pysm4.encrypt_ecb(str(Node_program.node_private_key), password) + "\n")
                file.write("@file_should_division\n")
                # 写入节点Ip
                file.write(pysm4.encrypt_ecb(str(Node_program.node_ip), password) + "\n")
                file.write("@file_should_division\n")
                # 写入节点port
                file.write(pysm4.encrypt_ecb(str(Node_program.node_port), password) + "\n")
                file.write("@file_should_division\n")
                # 写入当前区块链长度
                file.write(pysm4.encrypt_ecb(str(Node_program.node_blockchain_length), password) + "\n")
                file.write("@file_should_division\n")
                # 写入节点余额
                file.write(pysm4.encrypt_ecb(str(Node_program.node_balance), password) + "\n")
                file.write("@file_should_division\n")
                file.close()
                return True  # 返回处理结果
            else:
                return False
        else:
            return False

    # 读取其他用户节点数据文件的方法
    @staticmethod
    def read_other_normal_node_data():
        # 清空原有数据列表
        Node_program.other_normal_node_name_list.clear()
        Node_program.other_normal_node_public_key_list.clear()
        Node_program.other_normal_node_ip_list.clear()
        Node_program.other_normal_node_port_list.clear()
        Node_program.other_normal_node_balance_list.clear()
        # 判断相关文件是否存在
        if os.path.exists(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(Node_program.node_name) + "_folder\other_normal_node_data.txt"):
            file = open(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(Node_program.node_name) + "_folder\other_normal_node_data.txt", "r")
            counter = 0
            for item in file.readlines():
                if counter == 0:
                    Node_program.other_normal_node_name_list.append(item.strip("\n"))
                elif counter == 1:
                    Node_program.other_normal_node_public_key_list.append(item.strip("\n"))
                elif counter == 2:
                    Node_program.other_normal_node_ip_list.append(item.strip("\n"))
                elif counter == 3:
                    Node_program.other_normal_node_port_list.append(item.strip("\n"))
                elif counter == 4:
                    Node_program.other_normal_node_balance_list.append(item.strip("\n"))
                if counter == 4:
                    counter = 0
                else:
                    counter += 1
            file.close()
            return True
        else:
            return False

    # 重写其他用户节点数据文件的方法
    @staticmethod
    def update_other_normal_node_data():
        flag = False
        try:
            file = open(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(Node_program.node_name) + "_folder\other_normal_node_data.txt", "w")
            num = len(Node_program.other_normal_node_name_list)
            for i in range(0, num):
                file.write(Node_program.other_normal_node_name_list[i] + "\n")
                file.write(Node_program.other_normal_node_public_key_list[i] + "\n")
                file.write(Node_program.other_normal_node_ip_list[i] + "\n")
                file.write(Node_program.other_normal_node_port_list[i] + "\n")
                file.write(Node_program.other_normal_node_balance_list[i] + "\n")
            file.close()
            flag = True
        except IOError:
            Node_program.ready_text.config(state="normal")
            Node_program.ready_text.delete("1.0", "end")
            Node_program.ready_text.insert("end", "其他节点数据文件重写异常！")
            Node_program.ready_text.config(state="disabled")
        finally:
            return flag

    # 文件操作  读取并显示用户节点  所有文件名  的线程方法
    @staticmethod
    def logs_file_read_and_show_file_data_function():
        Node_file_program.memory_simulate_distribute_flag = False
        if os.path.exists(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(Node_program.node_name) + "_folder"):  # 判断该用户节点文件夹是否存在
            Node_program.ready_text.config(state="normal")
            Node_program.ready_text.delete("1.0", "end")
            Node_program.ready_text.insert("end", "文件读取中...\n")
            # 清空当前显示框
            Node_program.logs_file_show_file_text.config(state="normal")
            Node_program.logs_file_show_file_text.delete("1.0", "end")
            # 清空当前文件列表
            Node_program.logs_file_file_list.clear()
            # 获取具体的数据
            file_list = os.listdir(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(Node_program.node_name) + "_folder")
            Node_program.logs_file_file_sum = len(file_list)  # 获得文件总数
            for file in file_list:
                Node_program.logs_file_file_list.append(file)  # 文件名
                Node_program.logs_file_file_list.append(os.path.getsize(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(Node_program.node_name) + "_folder\\" + file))  # 文件大小
                Node_program.logs_file_file_list.append("NONE")  # 文件起始位置
                Node_program.logs_file_file_list.append("NONE")  # 文件终止位置
            # 调用虚拟内存分配的方法
            if Node_file_program.logs_file_area_plan(Node_program.logs_file_file_list):  # 判断分配结果
                Node_program.ready_text.insert("end", "区块分配成功\n")
                Node_file_program.memory_simulate_distribute_flag = True
            else:
                Node_program.ready_text.insert("end", "区块分配失败!\n")
            # 展示文件名列表
            Node_program.logs_file_show_file_text.insert("end", "序号:".ljust(4) + "文件名:".ljust(25) + "大小(单位byte):".ljust(12) + "起始位置:".ljust(10) + "终止位置:".ljust(10) + "\n")
            num = len(Node_program.logs_file_file_list)
            counter = 0
            for i in range(0, num, 4):
                Node_program.logs_file_show_file_text.insert("end", str(counter).ljust(6) + str(Node_program.logs_file_file_list[i]).ljust(28) + str(Node_program.logs_file_file_list[i+1]).ljust(16) + str(Node_program.logs_file_file_list[i+2]).ljust(14) + str(Node_program.logs_file_file_list[i+3]).ljust(14) + "\n")
                counter += 1
            Node_program.ready_text.insert("end", "文件读取完毕！")
            if Node_file_program.memory_simulate_distribute_flag is True:
                Node_program.logs_file_show_file_text.insert("end", "\n已为文件分配内存:{}byte,单个区块大小:{}byte,\n当前已用:{:.2f}%, 剩余{}byte可用.".format(Node_file_program.memory_simulate_max_distribution, Node_file_program.memory_simulate_single_block, ((Node_file_program.memory_simulate_max_distribution-Node_file_program.memory_simulate_free_area)/Node_file_program.memory_simulate_max_distribution) * 100, Node_file_program.memory_simulate_free_area))
            Node_program.logs_file_load_flag = True  # 文件是否读取成功的标志
        else:
            Node_program.ready_text.insert("end", "用户文件丢失！\n")
        Node_program.logs_file_read_target_file_flag = False  # 重置读取指定文件标志
        Node_program.logs_file_read_target_file_name = ""

    # 文件操作  创建指定文件的线程方法  返回创建结果
    @staticmethod
    def logs_file_create_file(file_name):
        Node_program.ready_text.config(state="normal")
        Node_program.ready_text.delete("1.0", "end")
        if os.path.exists(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(Node_program.node_name) + "_folder\\" + file_name):  # 判断文件是否存在
            return False
        else:
            file = open(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(Node_program.node_name) + "_folder\\" + file_name, "a")
            file.close()
            return True

    # 文件操作  读取指定并显示的文件的线程方法  返回读取结果
    @staticmethod
    def logs_file_read_file(file_name):
        if os.path.exists(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(Node_program.node_name) + "_folder\\" + file_name):  # 判断该文件是否存在
            # 清空当前显示数据
            Node_program.logs_file_show_file_text.config(state="normal")
            Node_program.logs_file_show_file_text.delete("1.0", "end")
            flag = True
            try:
                file = open(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(Node_program.node_name) + "_folder\\" + file_name, "r")
                Node_program.logs_file_show_file_text.insert("end", str(file.read()))
                file.close()
            except IOError:
                flag = False
            finally:
                return flag
        else:
            return False

    # 文件操作  修改指定文件的线程方法  返回创建结果
    @staticmethod
    def logs_file_rewrite_file(file_name, content):
        if os.path.exists(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(Node_program.node_name) + "_folder\\" + file_name):  # 判断文件是否存在
            file = open(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(Node_program.node_name) + "_folder\\" + file_name, "w")
            file.write(content)
            file.close()
            return True
        else:
            return False

    # 文件操作  删除指定文件的线程方法  返回删除结果
    @staticmethod
    def logs_file_delete_file(file_name):
        if os.path.exists(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(Node_program.node_name) + "_folder\\" + file_name):  # 判断该文件是否存在
            flag = True
            # 检测该文件是否可以删除
            if file_name == str(Node_program.node_name) + "base_data.txt":  # 用户节点数据文件
                flag = False
            elif file_name == "other_normal_node_data.txt":  # 其他节点数据文件
                flag = False
            elif file_name == "block_chain_data":  # 区块链数据文件夹
                flag = False
            # 判断是可以删除
            if flag is False:
                return False, 1
            else:
                os.remove(Node_file_program.file_folder_path + "normal(4.00)_node_" + str(Node_program.node_name) + "_folder\\" + file_name)
                return True, None
        else:
            return False, 0

    # 文件操作  模拟文件内存的分配方法
    @staticmethod
    def logs_file_area_plan(file_data_list):
        """
            为已知大小的文件分配在一定内存上的空间地址的分配
            输入：文件数据列表，至少包括 文件名，文件大小，分配起始位置，分配内存大小
            输出：已分配内存位置的文件数据列表，
            文件列表格式： 文件名  文件大小  起始位置  结束位置
        :param file_data_list:文件数据列表
        :return:True or False
        """
        flag = True
        # 获得当前文件数据列表数据
        file_num = int(len(file_data_list)/4)  # 获得文件总数
        file_sum_size = 0
        try:
            for i in range(0, file_num):
                file_sum_size += int(file_data_list[i * 4 + 1])
            if file_sum_size <= Node_file_program.memory_simulate_max_distribution:  # 判断是否超过了最大内存分配
                Node_file_program.memory_simulate_free_area = Node_file_program.memory_simulate_max_distribution - file_sum_size
                counter = Node_file_program.memory_simulate_start_address
                for i in range(0, file_num):
                    file_data_list[i * 4 + 2] = counter  # 获得文件起始地址
                    num = int(int(file_data_list[i * 4 + 1])/Node_file_program.memory_simulate_single_block)
                    if num * Node_file_program.memory_simulate_single_block < int(file_data_list[i * 4 + 1]):
                        num += 1
                    file_data_list[i * 4 + 3] = file_data_list[i * 4 + 2] + num * Node_file_program.memory_simulate_single_block
                    counter += num * Node_file_program.memory_simulate_single_block
            else:
                flag = False
        except ValueError:
            flag = False
        finally:
            return flag


# 创建客户端文件处理类
class File_program(object):
    def __init__(self):
        super().__init__()

    client_get_key_list_file_name_part = "(4.00)get_key_list_file.txt"

    # 定义创建用户公私钥对文件的方法
    @staticmethod
    def create_client_key_file():
        """
        创建用户所有的密钥文件,无返回
        :return: None
        """
        name = Main_program.name
        client_key_file_name = "client(4.00)" + str(name) + ".txt"  # 组合成用户目标文件
        if os.path.exists(client_key_file_name):  # 判断用户公私钥对数据文件是否存在
            pass
        else:
            client_key_file = open(client_key_file_name, "w+")  # 创建并打开目标用户文件
            client_key_file.write(str(Crypto_program.self_sm2_public_key) + "\n")  # 用户的SM2公钥
            client_key_file.write("@file_should_division\n")
            client_key_file.write(str(Crypto_program.self_sm2_private_key) + "\n")  # 用户的SM2私钥
            client_key_file.write("@file_should_division\n")
            client_key_file.write(str(Crypto_program.self_public_key) + "\n")  # 用户的身份公钥
            client_key_file.write("@file_should_division\n")
            client_key_file.write(str(Crypto_program.self_private_key) + "\n")  # 用户身份公钥对应的私钥
            client_key_file.write("@file_should_division\n")
            client_key_file.write(str(Crypto_program.self_share_public_key) + "\n")  # 用户的预共享公钥
            client_key_file.write("@file_should_division\n")
            client_key_file.write(str(Crypto_program.self_share_private_key) + "\n")  # 用户的预共享公钥对应的私钥
            client_key_file.write("@file_should_division\n")
            client_key_file.write(str(Crypto_program.self_share_public_key_sign) + "\n")  # 写入用户预共享公钥的签名
            client_key_file.write("@file_should_division\n")
            for key_item in Crypto_program.self_time_key_list:  # 遍历用户一次性公私钥对列表，将数据写入目标文件中
                client_key_file.write(str(key_item) + "\n")
                client_key_file.write("@file_should_division\n")
            client_key_file.close()  # 关闭用户目标文件

    # 定义从用户公私钥对文件中获取用户公私钥对数据的方法
    @staticmethod
    def get_client_all_key_data():
        # 初始化用户一次性公私钥对数据
        Crypto_program.self_time_key_list.clear()
        client_key_file_name = "client(4.00)" + str(Main_program.name) + ".txt"  # 组合成用户目标文件
        if os.path.exists(client_key_file_name):  # 判断当前用户文件是否存在
            client_key_file = open(client_key_file_name, "r")  # 以只读模式打开用户文件
            client_key_data_list = client_key_file.readlines()
            client_key_file.close()
            division_num = 1
            time_data = ''   # 用于存储暂时数据
            for client_data in client_key_data_list:
                if client_data.strip("\n") != "@file_should_division":
                    time_data += client_data
                else:
                    if division_num == 1:  # 用户SM2公私钥对
                        Crypto_program.self_sm2_public_key = time_data[0:len(time_data) - 1]
                    elif division_num == 2:
                        Crypto_program.self_sm2_private_key = time_data[0:len(time_data) - 1]
                    elif division_num == 3:  # 用户身份身份私钥对
                        Crypto_program.self_public_key = time_data[0:len(time_data) - 1]
                    elif division_num == 4:
                        Crypto_program.self_private_key = time_data[0:len(time_data) - 1]
                    elif division_num == 5:  # 用户预共享公私钥对
                        Crypto_program.self_share_public_key = time_data[0:len(time_data) - 1]
                    elif division_num == 6:
                        Crypto_program.self_share_private_key = time_data[0:len(time_data) - 1]
                    elif division_num == 7:  # 用户预共享公钥的SM2签名
                        Crypto_program.self_share_public_key_sign = time_data[0:len(time_data) - 1]
                    else:  # 用户的一次性公私钥对
                        Crypto_program.self_time_key_list.append(time_data[0:len(time_data) - 1])
                    time_data = ""  # 临时数据变量重置
                    division_num += 1  # 分割标志数加 1
            return True  # 返回获取结果
        else:
            return False

    # 定义修改用户公私钥对数据文件中一次性公私钥对的方法
    @staticmethod
    def update_client_all_data(time_public_key, time_private_key):
        client_key_file_name = "client(4.00)" + str(Main_program.name) + ".txt"  # 组合成用户目标文件
        # 将该一次性公私钥对从对应的列表中移除
        Crypto_program.self_time_key_list.remove(time_public_key)
        Crypto_program.self_time_key_list.remove(time_private_key)
        if os.path.exists(client_key_file_name):  # 判断用户公私钥对数据文件是否存在
            return False
        else:
            client_key_file = open(client_key_file_name, "w+")  # 以覆盖写的方式打开用户公私钥对的数据文件
            client_key_file.write(str(Crypto_program.self_sm2_public_key) + "\n")  # 用户的SM2公钥
            client_key_file.write("@file_should_division\n")
            client_key_file.write(str(Crypto_program.self_sm2_private_key) + "\n")  # 用户的SM2私钥
            client_key_file.write("@file_should_division\n")
            client_key_file.write(str(Crypto_program.self_public_key) + "\n")  # 用户的身份公钥
            client_key_file.write("@file_should_division\n")
            client_key_file.write(str(Crypto_program.self_private_key) + "\n")  # 用户身份公钥对应的私钥
            client_key_file.write("@file_should_division\n")
            client_key_file.write(str(Crypto_program.self_share_public_key) + "\n")  # 用户的预共享公钥
            client_key_file.write("@file_should_division\n")
            client_key_file.write(str(Crypto_program.self_share_private_key) + "\n")  # 用户的预共享公钥对应的私钥
            client_key_file.write("@file_should_division\n")
            client_key_file.write(str(Crypto_program.self_share_public_key_sign) + "\n")  # 写入用户预共享公钥的签名
            client_key_file.write("@file_should_division\n")
            for key_item in Crypto_program.self_time_key_list:  # 遍历用户一次性公私钥对列表，将数据写入目标文件中
                client_key_file.write(str(key_item) + "\n")
                client_key_file.write("@file_should_division\n")
            client_key_file.close()  # 关闭用户目标文件
            return True

    # 定义初始化获得 p, g 的方法
    @staticmethod
    def init_x3dh_p_g():
        p_file = open("Value_P.txt", "r")  # 打开目标文件
        Crypto_program.x3dh_p = int(p_file.read())  # 获取对应数据，并且将数据的格式转换
        p_file.close()
        g_file = open("Value_G.txt", "r")
        Crypto_program.x3dh_g = int(g_file.read())
        g_file.close()
        q_file = open("Value_Q.txt", "r")
        Crypto_program.x3dh_q = int(q_file.read())
        q_file.close()

    # 定义创建用户已获得公钥数据文件的方法
    @staticmethod
    def create_client_get_key_list_file(self_name):
        client_file_name = str(self_name) + File_program.client_get_key_list_file_name_part
        if os.path.exists(client_file_name):  # 检测该文件是否存在
            return False  # 返回创建结果
        else:  # 创建用户获得的公钥数据文件
            client_file = open(client_file_name, "a")
            client_file.close()
            return True

    # 定义读取用户已获得公钥数据文件的方法
    @staticmethod
    def get_client_get_key_list_file(self_name):
        # 初始化相关列表
        Crypto_program.other_get_key_name_list.clear()
        Crypto_program.other_get_time_key_list.clear()
        Crypto_program.other_get_x3dh_key_list.clear()
        Crypto_program.self_get_x3dh_time_key_list.clear()
        client_get_key_list_file_name = str(self_name) + File_program.client_get_key_list_file_name_part
        if os.path.exists(client_get_key_list_file_name):  # 检测该用户文件数据是否存在
            client_get_key_list_file = open(client_get_key_list_file_name, "r")  # 以只读模式打开用户文件
            client_get_key_list_content = client_get_key_list_file.readlines()
            client_get_key_list_file.close()
            key_num = len(client_get_key_list_content)
            for i in range(0, key_num):
                if i % 5 == 0:  # 用户名
                    Crypto_program.other_get_key_name_list.append(client_get_key_list_content[i].strip("\n"))
                elif i % 5 == 1:  # 一次性公钥
                    Crypto_program.other_get_time_key_list.append(client_get_key_list_content[i].strip("\n"))
                elif i % 5 == 2:  # x3dh 生成密钥
                    Crypto_program.other_get_x3dh_key_list.append(client_get_key_list_content[i].strip("\n"))
                elif i % 5 == 3:  # 己方为获得x3dh密钥临时生成私钥对应的公钥
                    Crypto_program.self_get_x3dh_time_key_list.append(client_get_key_list_content[i].strip("\n"))
                else:
                    pass
            return True  # 返回处理结果
        else:
            return False

    # 定义修改用户已获得的公钥数据文件
    @staticmethod
    def update_client_get_key_list_file(sign_flag, self_name, other_name, other_time_public_key, share_x3dh_secret_key, time_public_key):  # 参数依次为：模式(1 添加，2 删除)，当前用户名，被获取公钥的主人名， 一次性公钥，共享密钥, 主动进行X3DH计算临时生成的公钥
        client_get_key_list_file_name = str(self_name) + File_program.client_get_key_list_file_name_part
        if str(sign_flag) == "1":
            # 将新的已获得公钥数据添加至相关列表中
            Crypto_program.other_get_key_name_list.append(other_name)
            Crypto_program.other_get_time_key_list.append(other_time_public_key)
            Crypto_program.other_get_x3dh_key_list.append(share_x3dh_secret_key)
            Crypto_program.self_get_x3dh_time_key_list.append(time_public_key)
            # 打开相关文件
            if os.path.exists(client_get_key_list_file_name):  # 检测该用户文件数据是否存在
                client_get_key_list_file = open(client_get_key_list_file_name, "a")  # 以追加模式打开用户数据文件
                client_get_key_list_file.write(other_name + "\n")
                client_get_key_list_file.write(other_time_public_key + "\n")
                client_get_key_list_file.write(share_x3dh_secret_key + "\n")
                client_get_key_list_file.write(str(time_public_key) + "\n")
                client_get_key_list_file.write("@file_should_division\n")
                client_get_key_list_file.close()
                return True
            else:
                return False
        elif str(sign_flag) == "2":
            # 将该数据从相关列表中删除
            Crypto_program.other_get_key_name_list.remove(other_name)
            Crypto_program.other_get_time_key_list.remove(other_time_public_key)
            Crypto_program.other_get_x3dh_key_list.remove(share_x3dh_secret_key)
            Crypto_program.self_get_x3dh_time_key_list.remove(time_public_key)
            # 打开相关文件
            if os.path.exists(client_get_key_list_file_name):  # 检测该用户文件数据是否存在
                client_get_key_list_file = open(client_get_key_list_file_name, "w")  # 以重写模式打开用户数据文件
                data_num = len(Crypto_program.other_get_key_name_list)
                for i in range(0, data_num):
                    client_get_key_list_file.write(Crypto_program.other_get_key_name_list[i] + "\n")
                    client_get_key_list_file.write(Crypto_program.other_get_time_key_list[i] + "\n")
                    client_get_key_list_file.write(Crypto_program.other_get_x3dh_key_list[i] + "\n")
                    client_get_key_list_file.write(str(Crypto_program.self_get_x3dh_time_key_list[i]) + "\n")
                    client_get_key_list_file.write("@file_should_division\n")
                client_get_key_list_file.close()
                return True
            else:
                return False
        else:
            return False


# 创建图形界面类
class Window_program(object):
    def __init__(self):
        super().__init__()

    # 以下为窗口的相关参数
    screen_size = "1000x800+100+100"
    name = "基于X3DH的开发测试程序(客户端) v4.00"
    # 以下为图形化界面参数
    # 初始界面容器
    start_frame = ""
    # 注册界面容器
    register_frame = ""
    # 节点初始界面容器
    node_frame = ""
    # 节点创建界面容器
    node_create_frame = ""
    # 节点开启界面容器
    node_open_frame = ""
    # 用户节点主界面
    normal_node_main_frame = ""
    # 登录界面容器
    login_frame = ""
    # 用户界面容器
    interface_frame = ""
    # 公共聊天室界面容器
    public_chat_room_frame = ""
    # 客户端生成公私钥对界面容器
    interface_key_frame = ""
    # 服务端公钥展示界面容器
    show_sever_key_frame = ""
    # 客户端公钥展示界面容器
    show_client_key_frame = ""
    # 等待模式界面容器
    wait_mode_frame = ""
    # 聊天室模式 初始界面容器
    private_chat_mode_frame = ""
    # 聊天室模式  房主界面容器
    private_chat_host_frame = ""
    # 聊天室模式  成员界面容器
    private_chat_guest_frame = ""

    # 创建工具栏的方法
    @staticmethod
    def create_menu():
        # 创建工具栏
        root_menu = tk.Menu(root_window, )
        root_window.config(menu=root_menu)
        root_menu.add_command(label="帮助", command=Window_program.help_function)
        root_menu.add_command(label="关于", command=Window_program.about_function)
        root_menu.add_command(label="其他", command=Window_program.other_function)

    # 以下均为实现工具栏中的方法
    @staticmethod
    def help_function():
        messagebox.showinfo("帮助", "此版本仅仅完成了基本功能，若遇到以下问题: \n 1 退出按键失效：使用任务管理器将其关闭 \n 2 通信失败；请确保通信双方使用同一对系统")

    @staticmethod
    def about_function():
        messagebox.showinfo("关于", "这是基于X3DH协议的加密通信系统(客户端) v4.00 \n 作者: 信安21-1 任磊 \n 完成日期: 2023-12-??")

    @staticmethod
    def other_function():
        messagebox.showinfo("其他", "此版本尚且存在些许bug，如果可以的话，当多个用户使用时，请在客户之间交替使用时，彻底重启该客户端系统后，再登录其他用户")

    @staticmethod
    def deny_exit():
        messagebox.showwarning("警告", "您不能从此处退出客户端！", )

    # 定义导入图片并调整图片尺寸的方法
    @staticmethod
    def get_img(file, flag, width, height):
        if flag is True:  # 判断是否需要改变图像尺寸
            img = Image.open(file).resize((width, height))
        else:
            img = Image.open(file)
        return ImageTk.PhotoImage(img)

    # 定义清空根窗口的方法
    @staticmethod
    def clear_root_window():
        for item in root_window:
            item.destroy()

    # 定义清空容器内组件的方法
    @staticmethod
    def clear_frame(frame):
        for item in frame.winfo_children():
            item.destroy()


# 创建主程序类
class Main_program(object):
    def __init__(self):
        super().__init__()

    version = "4.00"  # 版本号
    name = ""  # 用户昵称暂存变量
    password = ""  # 用户密码暂存变量

    # 系统入口即初始界面的方法
    @staticmethod
    def start_application():
        # 调用初始化数据的方法
        Main_program.init_all_data()
        # 主菜单界面容器
        Window_program.start_frame = tk.Frame(root_window, relief="raised", bd=3, height=600, width=400)
        Window_program.start_frame.place(anchor="center", relx=0.5, rely=0.5)
        # 开启时的显示语
        tk.Label(Window_program.start_frame, text="基于X3DH的开发测试程序(带界面客户端)v4.00", font=("kaiti", 18), padx=25, pady=20, anchor="center").grid(row=0, padx=10, pady=10)
        tk.Label(Window_program.start_frame, text="请选择操作:", font=("kaiti", 18), padx=25, pady=20, anchor="center").grid(row=1, padx=10, pady=10)
        # 登录按钮
        tk.Button(Window_program.start_frame, text="登录", fg="blue", font=("黑体", 15), anchor="center", padx=15, pady=10, command=Main_program.start_window_to_login_window).grid(row=2, padx=10, pady=10)
        # 注册按钮
        tk.Button(Window_program.start_frame, text="注册", fg="blue", font=("黑体", 15), anchor="center", padx=15, pady=10, command=Main_program.start_window_to_register_window).grid(row=3, padx=10, pady=10)
        # 节点模式按钮
        tk.Button(Window_program.start_frame, text="节点模式", fg="blue", font=("黑体", 15), anchor="center", padx=15, pady=10, command=Main_program.start_window_to_node_window).grid(row=4, padx=10, pady=10)
        # 退出按钮
        tk.Button(Window_program.start_frame, text="退出", fg="red", font=('黑体', 15), anchor="center", padx=15, pady=10, command=Main_program.close_program).grid(row=5, padx=10, pady=10)

    # 初始界面转向其他功能界面的方法
    @staticmethod
    def start_window_to_login_window():
        Window_program.start_frame.destroy()
        Connection_program.login_window()

    @staticmethod
    def start_window_to_register_window():
        Window_program.start_frame.destroy()
        Connection_program.register_window()

    @staticmethod
    def start_window_to_node_window():
        Window_program.start_frame.destroy()
        Node_program.node_init_window()

    # 定义关闭客户端的方法
    @staticmethod
    def close_program():
        root_window.destroy()
        exit()

    # 定义初始化系统内数据的方法
    @staticmethod
    def init_all_data():
        Main_program.name = ""
        Main_program.password = ""
        Connection_program.hang_key_person_list = []
        Crypto_program.sys_time_key = None  # 系统默认生成的临时通行密钥
        Crypto_program.self_sm2_public_key = ""  # 用户SM2公钥
        Crypto_program.self_sm2_private_key = ""  # 用户SM2私钥
        Crypto_program.self_private_key = ""  # 用户的身份私钥
        Crypto_program.self_public_key = ""  # 用户的身份公钥
        Crypto_program.self_share_public_key = ""  # 用户的预共享公钥
        Crypto_program.self_share_private_key = ""  # 用户的预共享公钥的私钥
        Crypto_program.self_share_public_key_sign = "NONE"  # 用户的预共享公钥的签名
        Crypto_program.self_time_key_list = []  # 用户一次性公私钥对列表
        Crypto_program.x3dh_p = 0  # 默认情况下，取默认值
        Crypto_program.x3dh_g = 0  # 默认情况下，取默认值
        Crypto_program.x3dh_q = 0  # 默认情况下，取默认值

    # 清空当前屏幕的方法
    @staticmethod
    def clear_screen():
        # pyautogui.hotkey("Ctrl", "Shift", "Tab")
        pass


# 创建根窗口
root_window = tk.Tk()  # 设置根窗口
root_window.title(Window_program.name)  # 设置窗口名称
root_window.geometry(Window_program.screen_size)  # 设置窗口大小
root_window.config(background="azure")  # 设置背景颜色
root_window.attributes("-topmost", 1)  # 将窗口显示在最高级
Window_program.create_menu()  # 创建根界面工具栏
root_window.resizable(False, False)  # 设置使窗口大小不可变
root_window.protocol("WM_DELETE_WINDOW", Window_program.deny_exit)  # 设置限制，防止客户端非法退出运行
# 设置背景图片
canvas_window = tk.Canvas(root_window, width=1000, height=800)
# bg = Window_program.get_img("星空图1.webp", True, 1000, 800)
bg = Window_program.get_img("E:\绘画图源\星空图1.webp", True, 1000, 800)
canvas_window.create_image(500, 400, image=bg)
canvas_window.pack()


# 启动程序的入口
Main_program.start_application()


root_window.mainloop()
